Linq e il metodo Distinct

Ultimamente ho avuto la necessità di estrarre tutti gli elementi distinti di una query Linq. La query in questione interroga un EntitySet e restituisce come risultato una proiezione dei dati di una Entity all'interno di una classe; si presenta all'incirca così:

var result = (from c in dataContext.CaratteristicheChimicheSet where codition orderby order descending select new Chemical() { Alluminio = c.Al }

Le condizioni di uguaglianza delle istanze del risultato dipendono dalla proiezione e sono quindi definite in funzione di Chemical (ovvero della classe che uso come tipo di ritorno) e non delle Entity dell'EntitySet che sto interrogando; Chemical implementa a questo scopo i metodi Equals, GetHashCode e l'interfaccia IEquatable<Chemical>, definendo in questo modo le condizioni di uguaglianza di due istanze.

Cosa ho fatto quindi: un po' ingenuamente mi sono fidato delle apparenze, e per ottenere il set di risultati desiderato ho richiamato il metodo Distinct offerto da Linq sulla query succitata; morale della favola i risultati che ottenevo non erano quelli sperati, bensì era l'intero set di istanze con tanti "doppioni". In più i metodi di ugualianza di Chemical non venivano nemmeno lontanamente sfiorati.

Ho proseguito quindi nei miei tentativi: sono passato all'overload di Distinct che riceve in ingresso un IEqualityComparer; peggio di prima! il metodo "addirittura" non è supportato da LinqToEntities!

A questo punto ho deciso di fermarmi a ragionare e come al solito il ragionamento mi ha guidato ad una soluzione: LinqToEntities implementa il Distinct traducendolo in un Distinct sql, come si può osservare analizzando col profiler cosa succede sul DB all'invocazione del metodo Distinct senza parametri. Questa conclusione spiega perchè i metodi di uguaglianza implementati da Chemical non vengono considerati e perchè è corretto che LinqToEntities non supporti il Distinct che riceve un IEqualityComparer.

Forte di questa osservazione, è stato facile trovare la soluzione al mio problema. Eseguo la query, facendomi restituire tutti i risultati (duplicati compresi) in un array, tramite il metodo ToArray; sull'array risultante invoco il metodo Distinct. In questo scenario entra in gioco LinqToObjects che fa proprio quello che speravo: esegue i confronti di uguaglianza usando i metodi implementati da Chemical e restituendo quindi il set di istanze desiderato.

Qual è lo scopo di questo post? In sostanza volevo sottolineare due punti:

  • Esemplificare il funzionamento del metodo Distinct, in relazione al contesto in cui si usa, documentando quindi le differenze "sostanziali" tra l'implentazione di LinqToEntities e quella di LinqToObjects
  • Ho avuto una ulteriore conferma di come procedere "ad intuito" non aiuti a trovare le soluzioni ai problemi e men che meno a capire ciò che si sta facendo. Quando si incontra un problema "nuovo" conviene sempre soffermarsi a ragionare e capire "cosa ci sta dietro", piuttosto che buttarsi sulla prima apparente soluzione che ci viene offerta

 

Matteo

 

Print | posted @ mercoledì 7 gennaio 2009 18:52

Comments on this entry:

Gravatar # re: Linq e il metodo Distinct
by Fabrizio at 29/10/2009 14:02

Grazie, grazie, grazie! sto imparando linq,RIA Services,XAML,Silverlight (tutto in un botto!) e questa cosa del distinct con comparer non supportato da LinqToEntities mi ha fatto impazzire, adesso con ToArray ho risolto!
Comments have been closed on this topic.