.Net 3.5
LINQ to Sql e Guid autogenerati

Durante la realizzazione del layer di accesso ai dati di una semplice demo app, per il quale avevo scelto di utilizzare LINQ to Sql, sono incorso in un noioso bug nel recupero dei valori delle PrimaryKey, nel caso in cui questi siano autogenerati dal server di database.

Supponiamo di avere una tabella del tipo seguente, in cui la PK sia di tipo uniqueidentifier, automaticamente inizializzata per le nuove righe tramite la funzione di sistema newid():

image

Creiamo un nuovo DataContext di LINQ to Sql e importiamo al tabella creata; il designer crea una nuova entity con i campi omonimo delle colonne sul database:

image

Spesso, lato schema DB, i nomi delle chiavi contengono un riferimento alla tabella a cui appartengono. Per quanto riguarda le entità di dominio, invece, preferisco che gli identificativi si chiamino tutti allo stesso modo, sia per una questione di uniformità e leggibilità (non essendoci FK ma semplici riferimenti, non ho più la necessità di avere nomi diversi), sia perchè, ad esempio, potrei pensare di far implementare a tutte le mie entity un'interfaccia IHasIdentifier che esponga la proprietà Id e utilizzarla per implementare un GetById generico. Quindi, forte delle mie convinzioni, procedo alla modifica sulla entità di L2S generata dal designer:

image

Inoltre, mi ricordo anche di impostare, sulla property grid, che la proprietà Id è auto generata da DB e che deve essere recuperata dopo una query di Insert:

image

In fase di fetch, LINQ to Sql svolge egregiamente il suo lavoro, trasformando correttamente ogni condizione sulla proprietà Id in una where sulla colonna MySampleId:

image

image

Ciò purtroppo non accade quando, dopo una query di Insert, L2S tenta di recuperare il valore della chiave generata da database. Come si nota dalla query, infatti, viene erroneamente cercata una colonna chiamata Id, con successivo ed ovvio errore di Sql Server.

image

Ho segnalato il problema nei forum di MSDN, e mi è stato risposto che si tratta di un bug che verrà corretto con il rilascio del SP1. Attualmente ci sono solo due soluzioni:

  1. Utilizzare i medesimi nomi per proprietà e colonne
  2. Inizializzare manualmente la proprietà ad un nuovo Id sul costruttore della entity

Un'ultima curiosità: tutto ciò non si verifica nel caso in cui la PK sia un Identity e il motivo è che, in quel caso, Linq to Sql utilizza SELECT SCOPE_IDENTITY per recuperare il nuovo valore.

Technorati Tags:
5 Comments Filed Under [ .Net 3.5 ]
Costanti pubbliche? AHIAHIAHI

Premessa: ciò che scriverò è una banalità, ma secondo me in tanti non ne sono al corrente o non ci pensano. Di cosa parlo? Di cose del genere:

public const int MyConst = 10;

Il danno potenziale che le costanti pubbliche possono creare alla stabilità delle nostre applicazioni è enorme.

Why? Perché le costanti non sono altro che placeholder risolti in fase di compilazione. Questo vuol dire che, finché non si ricompila, il valore non viene aggiornato.

Implicazioni?

  1. Assembly A che definisce una costante MyConst = 10
  2. Assembly B che referenzia Assembly A e ne utilizza MyConst
  3. Assembly A cambia MyConst a 15
  4. Finché non ricompilo Assembly B, questo continua a vedere MyConst = 10

Ogni tanto mi capita di trovare righe di codice simili a quella in alto, con seguenti bug "strani" e dolori per scovarli. Ecco perché cerco sempre di abituare i junior che lavorano con me alla regola:

Le costanti devono essere sempre private o internal. Se serve esporle allora si utilizzino dei field readonly.

Augh!

Technorati tags: ,
[ADO.NET Entity Framework #0] Per iniziare

Ho da poco iniziato a studiare ADO.NET Entity Framework e vorrei pubblicare impressioni, tip, ecc.ecc. man mano che imparo qualcosa.

Il primo passo per iniziare a lavorare con questo ORM di Microsoft è quello di fare qualche download, per cui oggi mi limiterò a fornire qualche link utile per utilizzare la beta 3 (in attesa della definitiva) su VS2008. La lista della spesa è più o meno questa, in ordine di installazione:

  1. ADO.NET Entity Framework Beta 3: qui
  2. Patch per installazione su VS2008 RTM: qui
  3. ADO.NET E.F. Tools (CTP di dicembre 2007): qui
  4. SQL Server 2005, c'è la Express Edition scaricabile qui

That's all...

Per iniziare a smanettare, consiglio di dare un'occhiata a questo (MOOOOOLTO SEMPLICE) quickstart e a questo progetto su Codeplex

 

Technorati tags:
2 Comments Filed Under [ .Net 3.5 ]
A tool to manage your blog categories and Technorati Tags

When I first decided to have a blog, I didn't have a clear idea of what I was going to talk about. It was supposed to be focused on .Net and programming topics, indeed, but figuring out a list of categories having only this in mind was extremely hard. I think that a lot of bloggers had (and keep having) the same experience and, sudden or later, almost everyone comes to the need to re-arrange post categories.

Things get much more complicated when you decide to start Technorati-tagging your post: doing it post per post is pretty easy, just a matter of adding a couple of links. Some WLW plugins can be helpful to mantain a certain coherence on the keywords you are tagging, but what about the old posts? Can you figure out how boring and time consuming tagging old posts can be? I'm sure you can. I tried to do that job, giving up just some minutes after and deciding that I did need a tool to deal with it.

Though, I made Blog Manager (if you have a better name to suggest, please do it, I know that "Blog Manager" is simply awful smile_teeth) which uses MetaWeblog API to interact with blog engines and let you arrange Categories and Technorati tags with all those fancy features a Windows Explorer-like UI has, like multiple selection.

All you need to do is setting up your connection credentials

fetch some posts from your blog

and change categories and tags using multi-selection on the listview and three-state CheckBoxLists on the left

After your work is done, just press the Save button on the toolbar to update your blog.

An important reminder: Technorati Tags feature use regular expressions to extract keywords from each post body. Although both I and my friend Simone Chiaretta did many tests and it seems to work as expected, be aware that it can potentially mess your post text. So, please, do a backup of your blog data (there's a built in backup/restore feature in Blog Manager too) before using it.

Oh... and please always remember that...

This application is provided as is. The copyright holder cannot be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.

Here you can find both source code (in VS2008 beta 2 format) and executables.

EDIT: This project has been moved to Google Code and renamed as Blog Commander

Technorati tags: ,
6 Comments Filed Under [ .Net 3.5 ]
LINQ = Expression Trees

Quando scriviamo interrogazioni con LINQ, non dobbiamo mai perdere di vista ciò che in realtà esse sono, ossia alberi di funzioni e Lambda expression. Per questa ragione, un qualcosa come

1 var customers = db.Customers 2 .Where(c => c.CompanyName.StartsWith("A")) 3 .Join(db.Orders, 4 (c => c.CustomerID), 5 (o => o.CustomerID), 6 (c, o) => new { c, o }) 7 .Where(co => co.o.ShippedDate != null) 8 .Select(co => co.c).Distinct();

è, grazie a puro syntactic sugar, equivalente a

1 var customersLinq = (from c in db.Customers 2 join o in db.Orders 3 on c.CustomerID equals o.CustomerID 4 where c.CompanyName.StartsWith("A") && 5 o.ShippedDate != null 6 select c).Distinct();

Lo snippet di cui sopra infatti, non è altro che un modo leggibile per disegnare un Expression Tree. Questo concetto, che può sembrare un internal come un altro e quindi generare dei "chi se ne frega" allo stesso modo di un trattato sulle tradizioni popolari indocinesi, ha in realtà un peso determinante almeno per un paio di ragioni.

Intanto l'elaborazione non viene eseguita finchè non si cicla sul resultset; e questo, nel caso di LINQ to SQL, tanto per fare un esempio, vuol dire che finché non scriviamo

1 foreach (var item in customers) 2 { 3 Console.WriteLine(item.CompanyName); 4 }

non parte nessuna query verso il DataBase.

Inoltre, e anche in virtù anche del punto precedente, le interrogazioni LINQ possono essere concatenate tra di loro:

1 var customersStartingWithA = from c in db.Customers 2 where c.CompanyName.StartsWith("A") 3 select c; 4 5 var customersWithUnshippedOrders = (from c in customersStartingWithA 6 join o in db.Orders 7 on c.CustomerID equals o.CustomerID 8 where o.ShippedDate != null 9 select c).Distinct();

L'esempio, relativo a LINQ to SQL, genera questa query SQL:

SELECT DISTINCT [t0].[CustomerID], .... FROM [dbo].[Customers] AS [t0] INNER JOIN [dbo].[Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID] WHERE ([t1].[ShippedDate] IS NOT NULL) AND ([t0].[CompanyName] LIKE @p0)

che condensa perfettamente il concetto che siamo riusciti a scindere nelle due più semplici interrogazioni. Ah, attenzione che non sempre l'engine di LINQ to SQL è così smart, alle volte vengono fuori query innestate non da poco smile_teeth

Ovviamente quanto detto è uno dei fondamenti della stessa tecnologia LINQ, pertanto non è limitata solo a LINQ to SQL, ma a tutte le possibili incarnazioni che essa ha all'interno di .Net 3.5.

Technorati tags: ,
Add Comment Filed Under [ .Net 3.5 ]
Tre cosine che mi sono piaciute poco di LINQ to SQL

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 smile_wink) 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: ,
Add Comment Filed Under [ .Net 3.5 ]
Pensierini della sera su LINQ to SQL

In questi giorni sto spulciando un pochino questo ORM e fino ad ora le mie impressioni sono senz'altro positive; LINQ to SQL, a mio modo di vedere, è un prodotto che ha dalla sua un'estrema produttività, almeno per un paio di ragioni:

  1. Intanto l'ottima integrazione con il designer di Visual Studio, che si interfaccia con la base dati e ci consente di modellare il dominio applicativo veramente in brevissimo tempo: la comodità del designer del DataSet applicata ad un Domain Model + ORM, praticamente il mio sogno smile_teeth
  2. La semplicità e la naturalezza di LINQ come linguaggio di interrogazione, che ci consente di comporre (già, comporre, magari ne parlerò in un altro post) query complesse in maniera estremamente intuitiva e soprattutto strong typed (anche se alle volte si è costretti a smanettare con le lambda expression).

Ora.. è vero che il dominio viene "sporcato" dagli attributes, che c'è EntitySet per le collection e non una semplice interfaccia e che NHibernate rullezza, ma il mio pensiero in merito è più o meno "chi se ne frega" smile_teeth

Giuro che non avrei mai pensato di scrivere quel "chi se ne frega" di una riga fa, ma c'è una ragione: credo che LINQ to SQL sia, al giorno d'oggi, una soluzione estremamente valida per tutte quelle applicazioni - e sono tante - che difficilmente vedranno una versione 2.0. Per questa ragione un paragone con NHibernate è un pochino fuorviante e mal posto: il target è diverso, al massimo paragoniamolo ad Active Record e comunque consideriamolo un ORM dall'approccio molto più easy e anche parecchio RAD. Questo giustifica anche il punto 1 in alto, che magari avrà fatto storcere il naso a quanti, come il sottoscritto d'altronde, sono convinti che le entity di dominio vadano modellate a prescindere dallo schema del database.

Ovviamente non è tutto rose e fiori, ci sono aspetti che non mi hanno convinto fino in fondo, ma di questo scriverò (spero di averne il tempo) domani.

Technorati tags: , ,
One Comment Filed Under [ .Net 3.5 ]
Un semplice tool per gestire le categorie sul blog

Ne avevo parlato un paio di giorni fa. Vorrei riorganizzare le categorie sul mio blog, eliminando quelle poco usate ed assegnando i relativi post ad altre (nuove e non), ma sono sempre stato frenato dal fatto che farlo il manager web può essere veramente noioso ed estenuante.

Domenica scorsa allora, con un po' di tempo libero, mi sono messo a realizzare una semplice applicazione Windows Forms che, facendo uso delle MetaWeblog API, semplificasse di molto il lavoro; fatto sta che ho prodotto questa cosina qui:

1) Dopo aver configurato le impostazioni di accesso dal menu opzioni...

2) è possibile visualizzare le categorie e recuperare un certo numero di post dal proprio blog

A questo punto, grazie anche alle possibilità di filtro e di selezione multipla, è facile e veloce modificare le associazioni Post-Categorie nella CheckBoxList a sinistra.

Una nota importantissima:

Questo software è rilasciato gratuitamente "AS IS". L'autore (cioé il sottoscritto) non è in alcun modo tenuto a fornire assistenza né tantomeno potrà essere ritenuto responsabile per eventuali problemi inerenti il suo utilizzo. In altre parole, se vi si sminchia totalmente il blog, il sistema operativo, se un hacker accede al vostro conto in banca, ecc.ecc., non bussate alla mia porta!

Ciò detto, a questo link trovate i sorgenti.

Ah.. per inciso, le mie categorie sono ancora lì dov'erano smile_teeth

Technorati tags: ,
4 Comments Filed Under [ Misc .Net 3.5 ]
Linq e Reflector

Il più grande punto di forza di Microsoft LINQ è senza dubbio quel syntactic sugar che ci permette di scrivere query simil-SQL, strong typed e direttamente all'interno del codice C# (o VB.NET che sia).

Supponiamo di voler recuperare, dagli assembly in memoria, l'elenco delle classi che iniziano per una data lettera. In C# 3.0 posso scrivere qualcosa tipo

   1:  var types =
   2:      from assembly in AppDomain.CurrentDomain.GetAssemblies()
   3:      from type in assembly.GetTypes()
   4:      where type.Name.StartsWith("C") && type.IsClass
   5:      select new { Namespace = type.Namespace, Name = type.Name };
   6:   
   7:  foreach (var type in types)
   8:  {
   9:      Console.WriteLine("{0} \t {1}", type.Namespace, type.Name);
  10:  }

In realtà, ciò che avviene under the hood, è che il compilatore si fa carico di trasformare codice di questo tipo in qualcosa che sia traducibile in IL, facendo uso intensivo di extension methods, anonymous types, ecc.

Il risultato di tutto ciò è che, disassemblando quanto compilato con Reflector, ciò che ci si trova davanti è qualcosa del tipo...

Reflector disassemble

Morale: da domani, attenzione ad aver sotto mano anche i sorgenti veri e propri, perché Reflector da solo non basterà più.

Technorati tags: ,
Add Comment Filed Under [ .Net 3.5 ]