di .NET e di altre amenità

Entity Framework: Spostare le entità in un assembly separato (al contrario)

Nel mio precedente post ho mostrato una semplice soluzione per separate entità da DbContext, ottenuta "scorporando" i template T4 che sono usualmente generati dall'EDMX. Nella soluzione proposta in pratica ci saremmo trovati nella soluzione riportata nella figura qui accanto.

Tale soluzione, per quanto semplice da ottenere ed efficace, soffre di un problema che chiamaerei "logico". Se avete provato a manipolare un po' le entità mediante l'utilizzo del designer, dopo aver separato i t4, vi sarete resi conto che il diagramma delle entità è situato nell'assembly denominato "Data" anzichè, come ci si potrebbe aspettare, nell'assembly "Entities".

Dico che ce lo si potrebbe aspettare perchè logicamente appare abbastanza ovvio che il diagramma delle entità sia situato nel medesimo progetto in cui sono situate le entità che ne derivano. In realtà la questione è meramente di gusto personale. In effetti la presenza delle entità generate nell'assembly "Entities" non implica che esso debba avere un riferimento a "EntityFramework.dll", infatti tali entità sono "POCO" e quindi non portano alcun legame con l'EDM, se non il fatto di esserne generate. In effetti, potremmo benissimo decidere di scriverle manualmente ed Entity Framework le inghiottirebbe senza colpo ferire.

imageTuttavia, se questa questione vi causasse qualche problema, è del tutto possibile effettuare lo scorporamento nel modo diametralmente opposto. In tal caso sarà opportuno aggiungere il file EDMX al progetto "Entities" e in un secondo momento estrapolare il Samples.Context.tt e portarlo nell'assembly "Data". A questo punto, modificati path e referenze come spiegato nel post precedente (ma nell'assembly contrario) otterremo nuovamente una soluzione compilabile come nella figura successiva.

Il tutto con l'indiscutibile comodità di trovarsi con il designer nello stesso progetto delle entità. Ci troveremmo però ad avere una referenza a EntityFramework.dll indesiderata. Ma tale referenza dipende solo dalla genesi del progetto. Se la rimuovete manualmente vi renderete conto che il progetto compila alla perfezione anche senza.

A questo punto, la scelta tra le due ipotesi è del tutto personale. Lascio a voi ragionarci e magari fatemi sapere le ragioni delle vostre eventuali scelte.

Download: Elite.Samples.Architecture.zip (2,32MB)

Entity Framework: Spostare le entità in un assembly separato

Da qualche tempo sono tornato a sperimentare con l’Entity Framework. Nonostante prima Silverlight e recentemente le applicazioni Windows Phone e Windows Store mi stiano impegnando parecchio, soprattutto dal punto di vista della User Interface, mi capita molto spesso di avere a che fare con le problematiche di backend e architetturali. In questo post e nei prossimi vorrei mostrarvi una soluzione che ho adottato tempo fa con Entity Framework e sulla quale non ho mai avuto tempo di scrivere approfonditamente, ma che recentemente ho provato anche con EF5.0 scoprendo che è perfettamente applicabile.

Nel primo post vorrei dimostrarvi come sia possibile, con pochi e semplici passi, spostare le entità generate a partire dall’EDMX in un assembly separato. Usare Entity Framework ci regala un sistema di generazione del codice davvero potente, ma spesso ci fa scordare le buone pratiche e il rischio di mischiare le cose è sempre dietro l’angolo. Dal mio punto di vista, una volta scelto che le entità debbono essere POCO (cioè oggetti leggeri che non hanno dipendenze) la scelta di spostarle in un assembly dedicato è praticamente imprescindibile, non fosse altro che per mantenere ordine. Ecco quindi come procedere con EF5.0.

imageDiamo per scontato di aver generato una solution simile a quella riportata nella figura qui a lato. Il primo progetto "Data" è quello che conterrà il DataContext mentre il secondo progetto, denominato "Entities" servirà a contenere le entità generate da Entity Framework. L'unica accortezza preliminare è quella di creare un riferimento da "Data" a "Entities" dato che come intuibile la parte che rimane nel primo assmbly dovrà referenziare le entità. Come secondo passo è il momento di generare un EDMX, all'interno del progetto "Data", usando il template di Visual Studio 2012 (ma funziona anche con il 2010). Lascio a voi la scelta del database, basta che alla fine vi troviate con almeno una entità generata come riportato nella figura sottostante.

imageCon Entity Framework 5.0 il template automaticamente seleziona per noi una modalità di generazione del codice "DbContext", cioè delle entità che sono del tutto "pulite" da ogni riferimento a qualsivoglia classe base. Se infatti si apre il file "Person.cs", generato a partire dalla tabella "People" (sì, avete capito bene, People è plurale di Person e quindi il designer sceglie una entità del nome opportuno) vedrete che contiene esclusivamente le proprietà derivanti dalle colonne del database e null'altro.

Un'altra caratteristica di EF5.0 è che implicitamente installa I file .tt (template t4) che generano il codice ma questi file sono a nostra disposizione per eventualmente customizzare come il codice viene generato. Samples.Context.tt genera il DbContext mentre Samples.tt genera tutte le entità necessarie.

Ora, se si apre la cartella dei file del progetto "Data" e si prende il file Samples.tt, è possibile copiarlo nell'assembly "Entities". Questa operazione va fatta dal filesystem perchè Visual Studio non ci consente il cut & paste su questo item. Ma se poi, una volta copiato il file torniamo nel progetto "Data" ci sarà consentito di cancellare il file "Samples.tt". imageSulla sinistra riporto come appare il progetto dopo l'operazione.

Se si prova a compilare però ci si rende subito conto che la generazione delle entità fallisce con un errore. Il fatto è che il file TT che abbiamo spostato contiene un riferimento al file EDMX dal quale estrae le informazioni che gli servono per generare le entità. Avendo spostato il file dobbiamo correggere questa referenza e per farlo occorre modificare manualmente il file Samples.tt.

Modificare un file TT non è la cosa più semplice e intuitiva. Tanto per cominciare il codice non appare colorato e quindi pare di essere tornati a "emacs". In secondo luogo nemmeno l'intellisense ci viene in aiuto. L'unico sistema è quello "empirico" per cui si modifica e si genera provando a vedere se il risultato ottenuto è quello atteso. Solo in Visual Studio 2012 abbiamo un ottimo "Debugger" per I file TT che ci viene in aiuto quando proprio non ne veniamo fuori. Se proprio ne avete bisogno, potete scaricare l'ottimo "Tangible T4 editor" dalle estensioni di Visual Studio e sarete graziati da un editor decente. A questo punto, aprendo il file "Samples.tt" vedrete quanto segue nelle prime righe del file:

image

In particolare la linea che ci interessa è quella evidenziata. In questa riga dovremo riportare un path relativo cosicchè anche spostando il progetto in un'altra cartella esso sarà perfettamente compilabile. Nel mio caso il path è il seguente:

   1: const string inputFile = @"..\Elite.Samples.Architecture.Data\Samples.edmx";

Una volta modificata la linea e salvato il file Visual Studio ci mostrerà immediatamente i file delle entità generate diligentemente. Ma se si prova a compilare ci si scontra con un nuovo errore. L'errore è facilmente comprensibile: al DbContext generato nell'assembly "Data" mancano i riferimenti all'assembly delle entità. Non si tratta della referenza di progetto che dovremmo aver già creato ma banalmente dello "using". Apriamo quindi il file Samples.Context.tt, troviamo la riga dove appare "using System.Data.Entity.Infrastructure;" e aggiungiamo subito sotto le using all'assembly delle nostre entità. Nel mi caso "using Elite.Samples.Architecture.Entities;". In questo modo:

   1: using System;
   2: using System.Data.Entity;
   3: using System.Data.Entity.Infrastructure;
   4: using Elite.Samples.Architecture.Entities;

A questo punto il compilatore non si lamenta più. Due semplici modifiche ai template di generazione e ci ritroviamo DbContext ed entità in asembly separati, che compilano alla perfezione. Esattamente quello che stavamo cercando. Per I più pigri ecco il progetto ottenuto dai passi che vi ho riportato. Ricordate solo di modificare la password nel file di configurazione, laddove trovate YOURPASSWORDHERE. Poi tenetelo da parte per il prossimo post...

Download: Elite.Samples.Architecture.zip (2,32MB)

Entity Framework 4.0: Due webcast su Be-It

La scorsa settimana sono stati pubblicati due webcast su be-it - il sito di video di Microsoft Italia - che ho registrato recentemente. L'argomento è l'Entity Framework 4.0, che è stato rilasciato recentemente all'interno del Framework 4.0. I webcast sono i seguenti:

  1. Entity Framework 4.0: Introduzione
  2. Entity Framework 4.0: Le novità

Sono particolarmente contento del primo che è una semplice introduzione agli ORM, realizzata con poche slide animate per raccontare le problematiche dell'object realtional mapping attraverso la lente di Entity Framework. I vostri commenti su cosa migliorare sono ben accetti ovvaimente.

Ripetere operazioni con una Lambda Expression

Recentemente ho avuto la necessità di scrivere un batch in C# che nottetempo facesse delle operazioni un po' pesanti su un database, attingendo ai dati, compiendo elaborazioni e alla fine salvando i risultati nel medesimo database. Dopo un po' di test mi sono reso conto che il problema principale era dato dai timeout che saltuariamente il batch otteneva su alcune query con il rischio di compromettere l'integrità del lavoro.

Così, LINQ alla mano mi sono create un piccolo script che, presa in carico una operazione effettua un numero dato di tentativi intervallati da un ragionevole timeout così da dare il tempo al database di fare il suo lavoro.

   1: /// <summary>
   2: /// Does the retry.
   3: /// </summary>
   4: /// <param name="maxRetry">The max retry.</param>
   5: /// <param name="waitTimeout">The wait timeout.</param>
   6: /// <param name="action">The action.</param>
   7: public static void DoRetry(int maxRetry, int waitTimeout, Action<int> action)
   8: {
   9:     for (int current = 1; current <= maxRetry; current++)
  10:     {
  11:         try
  12:         {
  13:             action(current);
  14:             return;
  15:         }
  16:         catch (SqlException ex)
  17:         {
  18:             // TIMEOUT | DEADLOCK
  19:             if (ex.Number != -2 && ex.Number != 1205)
  20:                 throw ex;
  21:         }
  22:  
  23:         Thread.Sleep(waitTimeout);
  24:     }
  25: }

Lo script è davvero semplice e pulito. Chiede in ingresso il numero massimo di tentativi e il tempo di attesa, oltre ad una Action<int> ovvero una lambda expressione con l'azione da compiere. Poi fa un semplicissimo ciclo for che ad ogni iterazione chiama l'Action. Nel caso vada tutto bene esce altrimenti - in caso di timeout o di deadlock - attente il timeout e riprova. Naturalemente in caso di diversa eccezione il metodo notifica l'eccezione al chiamante. Ecco come usarlo:

   1: public void ExecuteLongRunningQuery(int parameter)
   2: {
   3:     Operations.DoRetry(5, 10000,
   4:         n =>
   5:         {
   6:             DataStore.LongRunningQuery(parameter);
   7:         });
   8: }

Poche righe e otteniamo di ripetere la query 5 volte intervallata di 10 secondi l'una dall'altra. Il parametro "n" che viene passato alla lambda è il numero di iterazione corrente e permette di scrivere in un ipotetico log il numero di tentativi effettuati.

Technorati Tags: ,

Entity Framework: Evitare problemi con il merge di file EDMX

Da un po' di tempo lavoro con e, nonostante tutti i conosciuti problemi, in azienda siamo riusciti ad addomesticarlo (o forse lui ha addomesticatio noi :P) e riusciamo a trarne vantaggio, nei limiti da esso imposti. In attesa della prossima versione che pare risolva buona parte dei problemi (ma al momento lo dico solo per sentito dire e non per esperienza diretta), vorrei darvi un tip su come gestire il merge di file EDMX (il Model di Entity Framework per intenderci) che se preso nel verso sbagliato è prolifico di errori.

L'origine del problema è da individuarsi in una formattazione "allegra" del file XML per cui il tag di chiusura di alcune sezioni viene messo in coda all'ultimo elemento figlio e non sulla riga successiva. Un esempio lo si vede nella parte superiore della seguente figura.

Comparazione Per quanto strano possa sembrare questo fatto mette in crisi il merge (io mi riferisco a Team Foundation Server) e spesso (o soprattutto) la persona che lo sta compiendo. Può accadere che aggiungendo una property ad una entità ci si trovi nel caso della parte inferiore della figura soprastante. Come si vede la proprietà Date diventa l'ultima dell'EntityType. Un merge manuale comporta la copia di entrambe le righe 107 e 108 ma come spesso accade (e direi "umanamente accade") si tende a copiare solo la riga 108 ottenendo quanto segue:

merged Inutile dire che il risultato è un errore di compilazione che (complice l'entity designer di Visual Studio) si traduce nel fallimento della generazione del codice e in qualche centinaio di incomprensibili errori... tutto ciò significa solo una cosa: tempo perso.

Dopo esserci caduto svariate volte ho elaborato una mia "strategia" personale per il merge di file edmx. L'unica cosa "sana" da fare è prevenire questo genere di errori aprendo manualmente da Visual Studio i due file da comparare nell'editor XML e grazie alla preziosa combinazione di tasti CTRL+SHIFT+D riformattare l'XML correttamente. Una operazioni di pochi istanti, che non richiede nemmeno l'apertura della solution, che però fa evitare errori inutili e forieri perdite di tempo. Una volta riformattati i file con questa combinazione infatti il codice sarà lineare e, sembra impossibile ma è così, si otterranno anche meno merge manuali.

Entity Framework: Il materiale del meeting

E' passata una settimana durante la quale ho un po' staccato. Naturalmente ho dimenticato di pubblicare i sorgenti e le slide dei meeting. Viste le incalzanti richieste eccomi finalmente a pubblicare il materiale che vi avevo promesso. Si tratta più o meno di una serie di esempi riguardanti l'Entity Framework che ho messo assieme mentre lo studiavo. Questi esempi poi sono diventati la base per la sessione dello scorso 12 Dicembre.

Approfitto per ringraziare i partecipanti che hanno dimostrato di apprezzare la sessione - nonostante l'argomento fosse un po' pesante - sia per mezzo dei feedback che contattandomi durante questi giorni per pormi qualche domanda.

Ed ecco il link al materiale: http://blog.boschin.it/download/entityframework.rar

Ancora grazie.

Technorati Tags: ,

Entity Framework vs LINQ TO SQL

Eccon un'utile tabella di paragone di alcune delle feature di Linq2SQL e Entity Framework.

Fonte: Entity Framework vs LINQ TO SQL

Days 08: Disponibile il codice della sessione

Ho appena messo online il codice e le slide della sessione che ho tenuto lo scorso 23 Ottobre a Padova in occasione dei Days 08. Chi fosse interessato ad approfondire troverà il materiale qui

http://blog.boschin.it/download/MSTour.Days08.zip (11,0 MB)

Entity Framework: Mappare procedure 'fuori ordinanza'

Chi arriva a Entity Framework partendo da Linq To SQL probabilmente dopo aver apprezzato molte migliorie come ad esempio il modello più vicino ad un ObjectModel quale ci si aspetta, probabilmente cadrà in un fase “depressiva” perchè si rende conto che oltre ad aver guadagnato qualcosa, nel contempo ha anche perso molto.

Non sto ad elencarvi questi casi, ma piuttosto mi vorrei concentrare su quello che mi è capitato oggi e che mi ha fatto perdere un bel po’ di tempo. In buona sostanza per Entity Framework esistono delle stored procedure “regolari” e altre per così dire “fuori ordinanza”. Se voi avete una stored procedure che vi restituisce un resultset sovrapponibile con una delle entity del vostro dominio allora non c’è problema, siamo nel campo delle procedure ammesse. Ma se per caso come oggi mi è capitato dovete fare una procedura che vi restituisce uno scalare o anche nulla, allora non c’è niente da fare... il designer di Entity Framework si rifiuta di prenderla in considerazione. O meglio: fa finta di fare il suo dovere ma poi vi molla sul più bello e cioè quando c'è da generare il codice che mappa la procedura nell'Object Context.

Per carità, se mettiamo sul piatto della bilancia i vantaggi rispetto agli svantaggi ce ne a sufficienza per prendere in considerazione EF, ma di fronte a queste cose verrebbe voglia di...

Comunque ecco come fare per gestire questo tipo di evenienze. Innanzitutto dovete creare la partial class che si sovrappone al vostro EDMX.

   1: public partial class MyEntities
   2: {
   3: }

Così facendo possiamo ora aggiungere la nostra procedura mappando i parametri su una stored procedure. Poniamo ad esempio di dover chiamare una sp denominata sp_Message_Post. Passiamo al designer e come di consueto mappiamo la procedura ricavandola dal Database con "Update model from database". Una volta che esce la lista delle procedure nel tab "Add" mettiamo la spunta sulla procedura e confermiamo l'aggiornamento.

A questo punto dobbiamo creare il "function import". Si tratta in buona sostanza dell'operazione con cui di informa il designer che una certa procedura va mappata su un metodo dell'ObjectContext e soprattuto che essa avrà un certo tipo di valore di ritorno. Nel Model browser si seleziona la procedure e con il tasto destro si sceglie "Create function Import". Diamo un nome a questa funzione, ad esempio "PostMessage" e un tipo di valore di ritorno, nel nostro caso nessuno.

Ed è qui che accade la cosa sconcertante. Se specificate che la vostra procedura ha un valore di ritorno scalare o non ce l'ha proprio il designer si considera sollevato dell'onere di creare il metodo nell'ObjectContext mentre solo nel caso in cui il valore sia una Entity allora il designer di degna di fare il proprio lavoro come si deve.

Allora ecco il codice da scrivere per immettere un metodo che wrappa il function import appena creato:

   1: public void PostMessage(
   2:     int companyId,
   3:     byte messageType,
   4:     byte priority,
   5:     byte deviceType,
   6:     string recipient,
   7:     string sender,
   8:     DateTime dateCreated,
   9:     byte[] messageBinary)
  10: {
  11:     EntityParameter companyIdParameter = 
  12:         new EntityParameter("companyId", DbType.Int32);
  13:     companyIdParameter.Value = companyId;
  14:     
  15:     // e così via per tutti i parametri...
  16:  
  17:     this.ExecuteFunction(
  18:         "PostMessage", 
  19:         companyIdParameter, 
  20:         messageTypeParameter, 
  21:         priorityParameter, 
  22:         deviceTypeParameter, 
  23:         recipientParameter, 
  24:         senderParameter, 
  25:         dateCreatedParameter, 
  26:         messageBinaryParameter);
  27: }

Potrebbe sembrare tutto, ma manca ancora un pezzetto. Bisogna infatti create una versione nuova del metodo ExecuteFunction che crei il command e faccia la chiamata, non alla procedura in questione ma al function import. Ecco il codice:

   1: protected void ExecuteFunction(string functionName, params EntityParameter [] parameters)
   2: {
   3:     DbCommand command = this.Connection.CreateCommand();
   4:     command.CommandType = CommandType.StoredProcedure;
   5:     command.CommandText = this.DefaultContainerName + '.' + functionName;
   6:  
   7:     foreach (EntityParameter p in parameters)
   8:         command.Parameters.Add(p);
   9:  
  10:     if (command.Connection.State == ConnectionState.Closed)
  11:         command.Connection.Open();
  12:  
  13:     try
  14:     {
  15:         command.ExecuteNonQuery();
  16:     }
  17:     finally
  18:     {
  19:         command.Connection.Close();
  20:     }
  21: }

In buona sostanza dobbiamo tornare ad "abbassarci" a gestire in proprio la connessione. Creiamo il command, assegnamo il nome del function import prependendo il "DefaultContainerName" cioè il namespace in cui vengono generati gli oggetti. In seguito aggiungiamo i parametri al comando e poi eseguiamo il tutto prendendoci l'onere di aprire la connessione se non lo è già e di chiuderla non appena terminato.

Tutto sommato è un po' di codice cui sicuramente non siamo nuovi. Ma la domanda è: perchè il designer non si assume questo onere per noi?

Technorati Tag:

Entity Framework: Generare le classi Entity da codice

Non so ancora esattamente a cosa mi potra' servire, ma esplorando l'entity framework ho scoperto che e' possibile generare le classi sulle quali sono mappate le entita' con poche righe di codice. Ho fatto la scoperta andando a disassemblare con Reflector il tool edmgen.exe che di solito viene usato per generare le entita' a partire dal modello concettuale, ovvero dal file con estensione CSDL.

Una volta che abbiamo aggiunto un riferimento a System.Data.Entity.Design possiamo accedere ad una classe EntityClassGenerator che con poche customizzazioni e' in grado di generare appunto il codice delle suddette classi. Ecco come:

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         LanguageOption options = LanguageOption.GenerateCSharpCode;
   6:  
   7:         EntityClassGenerator generator = new EntityClassGenerator(options);
   8:  
   9:         generator.GenerateCode(@"C:\Files\Entities.csdl", @"C:\Files\Generated.cs");
  10:     }
  11: }

Il metodo Generate() dispone anche di altri overload che consentono ad esempio di generare il file di destinazione in memoria per poi magari inserirlo in un assembly da compilare.

Come gia' detto al momento non ne vedo una utilita' pratica ma suppongo che pensandoci bene una la possiamo anche trovare. E se non fosse cosi' perlomeno qualcosa di nuovo lo ho imparato...

Linq: Un metodo generico per estrarre coppie nome-valore

Una delle cose che capitano piu' spesso realizzando l'interfaccia di un software e' la necessita' di estrarre delle coppie nome-valore per popolare oggetti quali le DropDownList, ma anche CheckBoxList e altri tipi di controllo. Quello che succede spesso e' che ci vediamo costretti a scrivere delle query ad-hoc, magari piu' di una per ogni tabella in modo tale da ottenere solo ed esclusivamente i due campi che ci servono.

Mediante l'uso di Linq2SQL e di Linq2Entities questo compito puo' essere semplificato notevolmente scrivendo un metodo che ci permette di personalizzare la lista estratta nelle sue varie "dimensioni".

Tipicamente abbiamo bisogno di:

  1. Estrarre solo due campi da una tabella che potenzialmente ne contiene molti. Ad esempio solo ID e Nome da una tabella di Province escludendo i dati di estensione, popolazione, etc...
  2. Filtrare gli elementi secondo semplici criteri. Ad esempio solo le Provincie di una determinata Regione
  3. Ordinare gli elementi in modo arbitrario. Ad esempio per Nome visualizzato piuttosto che per Estensione  o numero di abitanti

Grazie all'uso di Lambda Expression con il Framework 3.5 e' possibile esporre le caratteristiche elencate come parametri di un metodo e unendo a questo le potenzialita' dei generics ottenere facilmente qualunque lista in tempo pressoche' nullo. Ecco le due versioni del metodo

   1: // LINQ To SQL
   2:  
   3: static IEnumerable<Item> GetItems<T>(
   4:     Func<T, string> keyFunc,
   5:     Func<T, string> textFunc,
   6:     Func<T, bool> whereSelector,
   7:     Func<T, object> sortFunc)
   8:     where T : class
   9: {
  10:     using (ClassesDataContext dc = new ClassesDataContext())
  11:     {
  12:         return (from entity in dc
  13:                     .GetTable<T>()
  14:                     .Where(whereSelector)
  15:                     .OrderBy(sortFunc)
  16:                 select new Item
  17:                 {
  18:                     Key = keyFunc.Invoke(entity),
  19:                     Value = textFunc.Invoke(entity)
  20:                 }).ToArray();
  21:     }
  22: }
  23:  
  24: // LINQ TO Entities
  25:  
  26: static IEnumerable<Item> GetItems<T>(
  27:     Func<T, string> keyFunc, 
  28:     Func<T, string> textFunc, 
  29:     Func<T, bool> whereSelector, 
  30:     Func<T, object> sortFunc)
  31:     where T : EntityObject
  32: {
  33:     using (Entities entities = new Entities())
  34:     {
  35:         return (from entity in entities
  36:                     .CreateQuery<T>("[" + typeof(T).Name + "]")
  37:                     .Where(whereSelector)
  38:                     .OrderBy(sortFunc)
  39:                 select new Item
  40:                 {
  41:                     Key = keyFunc.Invoke(entity),
  42:                     Value = textFunc.Invoke(entity)
  43:                 }).ToArray();
  44:     }
  45: }

Il metodo, in entrambe le versioni espone 4 parametri che ci suggeriscono l'uso di una Lambda Expression:

  • KeyFunc specifica la chiave
  • textFunc specifica il valore
  • whereSelector ci consente di selezionare gli elementi.
  • sortFunc specifica il campo con cui ordinare gli elementi

L'unica sostanziale differenza tra i metodi per L2S e L2E e nel metodo che usiamo per ottenere accesso alla "tabella" grezza degli elementi. Mentre il DataContext di L2S espone un metodo GetTable<T>() con L2E dobbiamo creare una semplice query che ha come parametro il nome della entity stessa e per questo dobbiamo usare CreateQuery<T>(query);

Ecco come usare il metodo:

   1: static void Main(string[] args)
   2: {
   3:     foreach (Item item in GetItems<Course>(
   4:         a => a.CourseID.ToString(), 
   5:         b => b.Title, 
   6:         c => true, 
   7:         d => d.Title))
   8:     {
   9:         Console.WriteLine(item.Key + " - " + item.Value);
  10:     }
  11:  
  12:     Console.ReadLine();
  13: }

I parametri specificati otterranno una lista di Item - definiti come classi con una proprieta' Key e una Value - dove la chiave sia il valore di CourseID e il testo e' dato da Title. Specificando "true" come terzo parametro otterremo tutti gli elementi della tabella. Infine con il quarto parametro chiediamo di ordinare per Title.

Ho usato questa tecnica in un progetto recente in cui avevo molte form zeppe di DropDownList e devo dire che mi ha fatto risparmiare un bel po' di tempo. Il bello e' che scrivere i parametri e' molto semplice perche' l'intellisense si accorge del tipo che stiamo usando e quindi ci propone i membri della classe tra i quali possiamo comodamente scegliere.

Resharper 4.0: Una strana politica nei "var"

Sto provando Resharper 4.0 da qualche giorno e come al solito lo trovo uno strumento utile e ben fatto che come dalla versione 3.0 è anche finalmente "delicato" nell'uso delle risorse della macchina e di conseguenza maggiormente usabile.

Quello che mi ha un po' indispettito è l'abitudine di Resharper di suggerire l'uso indiscriminato della keyword "var". E' pur vero che questo non ha alcun impatto nell'applicazione, ma la leggibilità del codice ne perde e anche parecchio. Perciò a mio parere la prima cosa da fare non appena installato Resharper è di recarsi nelle opzioni e sotto Code Inspection > Inspection Severity disabilitare le ultime due opzioni della sezione Code redundancies in particolare quelle che recitano:

  • Use 'var' keyword when initializer explicitly declares type
  • Use 'var' keyword when possible

Un bel "Do not show" a queste opzioni ricondurra Resharper alla ragione e ci lascerà scrivere il codice così come si dovrebbe fare cioe esplicitando il tipo ovunque possibile. A mio parere l'uso della keyword 'var' è legittimo esclusivamente quando abbiamo a che fare con degli anonymous types. Ogni altro uso è sostanzialmente uan illegittima scorciatoia.

Technorati Tags: ,