Tutti conosciamo i Dire Straits, vero? Bene.
La miglior formazione dei Dire Straits, a mio avviso, è stata quella composta da:
Se provassimo a mappare il tutto in un modello ad oggetti, potremmo scrivere:
public class Band { public int BandId { get; set; } public IList<Player> Members { get; set; } } public class Player { public int PlayerId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public Band Band { get; set; } }
E ora che abbiamo Linq2NHibernate possiamo scrivere una cosa del tipo:
using (ISession session = SessionHelper.OpenSession()) { Band myBand = session.Linq<Band>().Expand("Members") .Where<Band>(bnd => bnd.BandId == 1) .FirstOrDefault<Band>(); Console.WriteLine("Nome band: {0}, numero di componenti: {1}", myBand.Name, myBand.Members.Count); }
L'output però non è quello che ci aspettiamo:
Nome band: Dire Straits, numero di componenti: 1
La causa è nel codice SQL generato da Linq2NHibernate, che, da Profiler, risulta essere questo:
exec sp_executesql N'SELECT top 1 this_.BandId as BandId4_1_, this_.Name as Name4_1_, members2_.BandId as BandId3_, members2_.PlayerId as PlayerId3_, members2_.PlayerId as PlayerId2_0_, members2_.FirstName as FirstName2_0_, members2_.LastName as LastName2_0_, members2_.BandId as BandId2_0_ FROM dbo.Band this_ left outer join dbo.Player members2_ on this_.BandId=members2_.BandId WHERE this_.BandId = @p0',N'@p0 int',@p0=1
In pratica, la chiamata a FirstOrDefault() aggiunge quel TOP 1 all’SQL generato, che fa sì che venga ritornata solo una riga ritornata dal DB, falsando il conteggio.
I modi per risolvere la questione sono due:
- Tornare ad usare la Criteria API :).
- Sostituire FirstOrDefault<Band>() con ToList<Band>()[0].
In questo modo, la clausola TOP sparisce e i Dire Straits tornano ad essere cinque:
Nome band: Dire Straits, numero di componenti: 5
Technorati Tags:
.NET,
NHibernate,
Linq