2016-05-27 1 views
0

die einfache Beziehung zwischen Mitarbeitern Betrachten und Firmenmodellen (viele zu viele):Inklusive Methode (n + 1 Ausgabe) nicht mit einer Push-Methode arbeiten, aber tut mit + =, wenn auf einen Array zuweisen

Firmenmodell :

has_many :employees, through: :company_employees 
has_many :company_employees 

Mitarbeitermodell:

has_many :companies, through: :company_employees 
has_many :company_employees 

CompanyEmployee Modell (Join-Tabelle):

belongs_to :employee 
belongs_to :company 

auch Besitzer Modell:

has_many :companies 

Also in meinem System, ich habe einen Eigentümer, die mehrere Unternehmen und Arbeitnehmer haben können, die gegebenen arbeiten für mehrere Unternehmen.

Nun, in meiner Mitarbeiter Controller ich will alle Mitarbeiter für einen Eigentümer Workin holen:

def owners_linked 
@company_employees = [] 
owner.companies.each do |company| 
    @company_employees.push (company.company_employees.includes(:company, :employee)) # when += instead of push - it works 
end 
respond_to do |format| 
    format.js {render "employees_list"} 
end 
end 

Ich brauche einen Zugriff auf Mitarbeiter Instanzen haben (persönliche Daten), company_employees Tabelle (Informationen über die Position im Unternehmen) und Unternehmen (unternehmensbezogene Daten).
Um n + 1 Problem zu lösen und die Leistung zu beschleunigen, verwende ich enthält Methode. Nun, das ist das Problem, dass in meinem Controller-Aktion in Zeile:

@company_employees.push company.company_employees.includes(:company, :employee) 

wenn Push Methode verwendet es funktioniert nicht. Ich erhalte den Fehler in der Ansicht, dass die Mitarbeitermethode nicht definiert ist. Auf der anderen Seite, wenn ich den Push zu + = Zeichen ändern funktioniert es einwandfrei.

Kann mir jemand helfen zu verstehen, warum es so ist?
Ich weiß, dass + = ineffizient ist, also würde ich lieber nicht dabei bleiben.

Antwort

0

Dies hat nichts mit Ihrer Verwendung von Includes zu tun.

Wenn Sie += verwenden, enden Sie mit einem Array von CompanyEmployee Objekte. Wenn Sie jedoch push verwenden, verketten Sie keine Arrays mehr, sondern erstellen ein Array von Collections. Sie rufen dann employee auf der Sammlung und nicht ein Element der Sammlung, weshalb Sie einen Fehler erhalten.

Persönlich würde ich dies als

@company_employees = owner.companies.flat_map do |company| 
    company.companee_employees.include(...) 
end 

schreiben Obwohl ich so aus Gründen der Prägnanz tun würde, anstatt Leistung. Jeder Leistungsunterschied zwischen += und anderen Arten der Verkettung von Arrays ist winzig im Vergleich zu der Zeit, die zum Abrufen von Daten aus der Datenbank benötigt wird.

Dies löst jedoch nicht vollständig Ihr n + 1 Problem, da die Daten für jedes Unternehmen separat geladen werden. Ich würde tun

@company_employees = owner.companies.include(company_employees: [:company, :employee]).flat_map(&:company_employees) 

Welche nicht so viele Abfragen.

0

Normalerweise greife ich das an, indem ich von der anderen Seite hereinkomme. Ich glaube, das bekommen, was Sie suchen:

@company_workers = Employee.where(company_id: owner.companies.pluck(:id)) 

die where(company_id: ...) kann ein Array übernehmen und automatisch ein in(...) Befehl in SQL eingerichtet werden soll.

die SQL werden also, etwas wie am Ende:

select * from employees where company_id is in(1,2,3,4) 

Mit dem 1, 2, 3, 4 sind die Gesellschaft IDs des Besitzers.

Verwandte Themen