ho questo oggetto grafico:LINQ to NHibernate ThenFetch più proprietà
// Lots of stuff omitted for brevity; these are all virtual properties and there
// are other properties which aren't shown on all classes.
class A {
B b;
C c;
DateTime timestamp;
}
class B {
X x;
Y y;
}
class X {
int id;
}
class C { }
class Y { }
or to put it more simply,
a = {
b: {
x { id: int },
y: { }
},
c: { },
timestamp: DateTime
}
Ora sto facendo una query in cui ho intenzione di restituire un elenco di A
s e ho bisogno tutti i loro B
s , C
s, X
s e Y
s. Vado anche a raggrupparli per B in una ricerca.
ILookup<B, A> GetData(List<int> ids) {
using (ISession session = OpenSession()) {
var query = from a in session.Query<A>()
where ids.Contains(a.b.x.id)
orderby A.timestamp descending
select a;
query = query
.Fetch(a => a.b)
.ThenFetch(b => b.x)
.Fetch(a => a.b)
.ThenFetch(b => b.y)
.Fetch(a => a.c);
return query.ToLookup(a => a.b);
}
}
Un paio di cose da notare:
- Questo è un rapporto in cui deve essere restituito tutti i dati - i risultati illimitati non è un problema.
- Sto facendo il raggruppamento utilizzando
ToLookup
perché l'utilizzo digroup by
sembra essere più complicato quando sono necessari tutti i valori effettivi: è necessario interrogare il database per i gruppi e quindi per i loro valori effettivi.
La mia domanda è come specificare correttamente la strategia di recupero. Il modo in cui l'ho fatto è l'unico modo che ho trovato per questo a correre (avendo recuperato tutte le bx e dai valori) - ma produce SQL che sembra sbagliato:
select /* snipped - every mapped field from a0, b1, x2, b3, y4, c5 - but not b6 */
from [A] a0
left outer join [B] b1
on a0.B_id = b1.BId
left outer join [X] x2
on b1.X_id = x2.XId
left outer join [B] b3
on a0.B_id = b3.BId
left outer join [Y] y4
on b3.Y_id = y4.YId
left outer join [C] c5
on a0.C_id = c5.CId,
[B] b6
where a0.B_id = b6.BId
and (b6.X_id in (1, 2, 3, 4, 5))
order by a0.timestamp desc
Come si può vedere si sta facendo il valore per a.b
3 volte - b1
e b3
per il recupero e b6
per la clausola where.
- Suppongo che questo abbia un impatto negativo sulle prestazioni del DB - sono corretto?
- C'è un modo per modificare le mie chiamate
.Fetch
in modo che recuperi solo una voltaa.b
? - È un buon approccio al mio problema?
Prima di tutto, questi sono tutti molti a uno come si può vedere dalla mappatura (c'è solo una B in una A, e non una lista di essi), quindi l'intera query caricherà solo 4 entità. In secondo luogo, quello che stai suggerendo è esattamente l'opposto di quello che vorrei - invece di ridurre la complessità della query l'hai aumentato dividendolo in più query. La query ideale avrà i seguenti join: 'da [A] join esterno sinistro [B] in ...left outer join [X] on ... left outer join [Y] on ... '. – configurator
Il mio commento precedente sembra duro; Non volevo impedirti di cercare di aiutare. Apprezzo il tuo sforzo, anche se non sembra come dal mio precedente commento. – configurator
Ho verificato il comportamento suggerito riguardo alle entità correlate al precaricamento. Usando NHibernate Profiler posso vedere che sono recuperati solo una volta, quindi posso confermare che ciò che dice bdrajer è vero sulla memorizzazione nella cache dei dati nella sessione. –