Ieri ne ho parlato tessendone le lodi, perchè tutto sommato reputo LINQ un buon ORM, che forse però soffre di qualche peccato di gioventù. Visto che per natura sono un po' rompiballe e non mi accontento mai, infatti, vi vengo a raccontare un paio di aspetti (anzi tre) che mi sono subito saltati all'occhio e che non mi sconfinferano granché.
Punto 1
Le entity (generate da un'ottimo designer, poco da dire) non sono serializzabili a causa delle dipendenze da EntitySet e EntityRef. Si tratta di una brutta limitazione, che non mi permette di esporle direttamente MBV con Remoting, tanto per fare un esempio, non mi permette di memorizzarle in un Session Server, non mi permette di scriverle nel ViewState se mi voglio fare del male (o se non lo memorizzo in pagina ) and so on...
Punto 2
Le query SQL prodotte sono a volte di dubbia ottimizzazione. Se ad esempio scrivo
1 var orders = from o in Orders where o.Customer.Id == 5;
LINQ mi spara una bella JOIN tra la tabella degli ordini e quella dei clienti, mentre invece la condizione potrebbe essere posta utilizzando esclusivamente la prima (come fa NHibernate):
SELECT [t0].[OrderID], ... altri fields ...
FROM [dbo].[Orders] AS [t0]
LEFT OUTER JOIN [dbo].[Customers] AS [t1]
ON [t1].[CustomerID] = [t0].[CustomerID]
WHERE [t1].[CustomerID] = @p0
Per ovviare a questo problema, l'unico modo è esporre una proprietà CustomerID anche nella classe Order, come d'altronde fa per default il designer. "Stilisticamente" non è il massimo, ma quantomeno, se generiamo il codice da designer di Visual Studio, il setter della proprietà CustomerID solleva un'eccezione se proviamo ad impostarne un valore diverso da quello di Order.Customer.ID.
Punto 3
Piccola premessa: in LINQ to SQL ogni associazione è lazy by design (ed è una best practice); ma attenzione a chiamare la Dispose di un oggetto DataContext se gli oggetti recuperati con esso non sono stati completamente inizializzati. Consideriamo ad esempio questo metodo:
1 public Customer GetCustomerById(int id)
2 {
3 using (MyDomainDataContext db = new MyDomainDataContext())
4 {
5 // Recupero il customer dato il suo Id, ma attenzione:
6 // la collection customer.Orders è lazy loaded e quindi
7 // sarà inizializzata solo al primo accesso
8 return db.Customers.First(c => c.Id == id);
9 }
10 }
Ora, dato che la collection Orders, ancora non inizializzata, ha al suo interno una reference a *quello specifico* DataContext che l'ha creata; pertanto, accedere alla proprietà Orders al di fuori di questo metodo causerà una ObjectDisposedException. Fin qui me l'aspetto e lo trovo anche giusto. Attenzione però che, anche agganciando quel customer ad un altro DataContext tale reference non viene aggiornata e quindi si otterrà comunque un'eccezione.
Technorati tags:
LINQ,
.Net 3.5