2009-12-15 4 views
9

Sto provando a recuperare con impazienza le raccolte utilizzando selects, ma tutto ciò che sono get è inner join. Cosa sta succedendo?Forza una selezione desiderosa in NHibernate

Session.CreateCriteria(typeof(Foo)) 
    .SetFetchMode("Bars", FetchMode.Select) 
    .CreateAlias("Bars", "b") 
    .SetFetchMode("b.Bazes", FetchMode.Select) 
    .List(); 

Ho provato a cambiare FetchMode a Eager, ma che non funziona - ho ancora ottenere inner join invece che seleziona separati. Non sono sicuro di dove sia persino il join interno, perché nulla nei documenti parla di FetchMode che causa interazioni interne. È possibile ottenere selezioni desiderosi?

Aggiornamento OK Ho calcolato che la creazione di un alias provoca un join interno. Quindi posso usare .CreateAlias ​​("Bars", "b", JoinType.None), ma poi il recupero di b.Bazes ritorna al caricamento lazy. Urgh.

risposta

1

Un JOIN INNER è il modo in cui NHibernate carica i record e i relativi record figlio. Questo è generalmente il modo più efficiente per farlo.

Se si desidera utilizzare più istruzioni SELECT, la query per i bambini dovrebbe in qualche modo includere i criteri per il genitore. Un INNER JOIN semplifica l'accesso ai bambini appena imparentati, NHibernate lo dividerà correttamente in più entità dopo aver eseguito la query.

Credo che Entity Framework 4 ti consenta di eseguire più query e 'magicamente' ricollegare gli oggetti correlati, ma non sono a conoscenza di NHibernate che possiede tale funzionalità (sono sicuro che qualcuno mi correggerà se lo sono sbagliato su questo).

+0

Ma il tipo di join predefinito è in genere left outer join no? I join interni non funzionano se la chiave esterna è nullable, o come nel mio caso, dove i bar potrebbero essere vuoti. Anche i documenti sembrano indicare che puoi fare una scelta entusiasta. – cbp

0
Session.CreateCriteria(typeof(Foo)) 
    .SetFetchMode("Bars", FetchMode.Select) 
    .CreateAlias("Bars", "b") <-- this line triggers a join (think) 
    .SetFetchMode("b.Bazes", FetchMode.Select) 
    .List(); 

Se davvero non si vuole unisce è possibile specificare recuperare = "select" nella mappatura, ma che potrebbero causare un N + 1 di selezione che non è raccomandato (uno selezionare per ogni entità Foo, e poi uno per ogni Baze)

1

Per le entità di carico meno pericolose, viene utilizzata l'unione esterna sinistra. Quindi è necessario modificare il codice in questo modo:

Session.CreateCriteria(typeof(Foo)) 
.SetFetchMode("Bars", FetchMode.Select) 
.CreateAlias("Bars", "b", JoinType.LeftOuterJoin) 
.SetFetchMode("b.Bazes", FetchMode.Select) 
.List(); 

mi ha aiutato a similar scenario.