none
aggiornare il model di EF 5 - decorare con attributi le proprietà autogenerate RRS feed

  • Domanda

  • Ciao a tutti!

    Sto prendendo confidenza da poco con MVC4 + Entity Framework

    Non mi è ancora chiaro come procedere quando voglio fare qualche modifica sulle classi autogenerate da EF. Ad esempio mi è capitato di incorrere in questo problema: ho decorato molte proprietà del mio model con

    <Display(Name:="Nome visualizzato">

    Poi ho fatto una modifica sul designer di EF - una cosa di cui mi sono pentito - ho cambiato il nome di una 'proprietà di navigazione' - non funzionava più niente e ho ridigitato il nome originario.

    Risultato: dalle classi autogenerate sono scomparsi tutti i miei attributi.

    Sbaglio qualcosa? E' corretto decorare manualmente le proprità autogenerate con attributi e in generale modificare manualmente il model? Se sì, come evitare i problemi in cui sono incorso io?

    Quando in futuro avrò modifiche sul db, potrò aggiornare il model senza diventare matto?

    Marco


    martedì 8 ottobre 2013 10:11

Risposte

  • Ciao Marco,

    non è semplice perché non conosco la logica che vuoi applicare alla nominazione, quindi prendilo proprio come un esempio che poi tu dovrai finire di elaborare.

    public string PropertyMetaDataDisplayName(EdmProperty edmProperty)
    {
        //Qui devi inserire la tua logica di nominazione
        //Per esempio partendo dal nome originale della proprietà
        var propertyName = edmProperty.Name
        
        //E poi elaborandolo secondo la logica che vuoi applicare
        var displayName = .....
    
        //Una volta definito il nome che vuoi visualizzare
        return string.Format(
            CultureInfo.InvariantCulture,
    	"<Display(Name:=\"{0}\")>",
    	displayName);
    }

    Questa funzione la puoi inserire nel file tt subito prima della funzione che definisce e genera le firme delle proprietà, per semplificarti la ricerca ti virgoletto la firma della funzione che devi cercare "public string Property(EdmProperty edmProperty)".

    Come ti dicevo nel post precedente una volta definita e inserita la funzione che definisce e genera il tuo attributo, devi inserire l'invocazione della funzione tra le direttive di generazione delle proprietà, la direttiva che devi cercare è la seguente "<#=codeStringGenerator.Property(edmProperty)#>" e la direttiva che devi aggiungere subito prima è "<#=codeStringGenerator.PropertyMetaDataDisplayName(edmProperty)#>".

    Arrivati a questo punto tieni presente che la logica di generazione considera ed elabora le proprietà suddivise in SimpleProperties per le proprietà semplici e ComplexProperties per le proprietà di navigazione, le NavigationProperty, quello che avrai inserito, arrivato a questo punto, sarà per le SimpleProperty se ti dovesse interessare farlo anche per le NavigationProperty non dovrai far altro che replicare il tutto con le dovute semplici modifiche anche per le Navigation, considera che sia le funzioni di generazione, sia le direttive di invocazione si trovano successive a quelle che hai inserito.

    Una volta terminato, selezionando con il tasto destro del mouse il file tt nel Solution Explorer, dal menù di popup puoi eseguire il debug passo passo di quanto fatto selezionando "Debug T4 Template", naturalmente prima dovrai inserire gli opportuni punti di interruzione dove ti interessa.

    Spero di essere stato sufficientemente chiaro ed esaustivo

    Pierluigi

    • Contrassegnato come risposta Marco Migani giovedì 10 ottobre 2013 13:44
    giovedì 10 ottobre 2013 11:16
  • Ciao Marco,

    probabilmente non ci siamo capiti, dal titolo del primo post sembrava che tu stessi utilizzando EF 4, ma da quanto scrivi in questo secondo si evince che tu stai utilizzando EF 5; sarebbe anche utile sapere che versione di VS stai utilizzando. Se stai utilizzando EF 5 con VS2012, non devi aggiungere nessun Template, questo perché li aggiunge già di defaut, infatti se vai a vedere il contenuto del ramo del file EDMX nel Solution Explorer, troverai già due file con estenzione tt uno relativo alla generazione delle POCO Entities e l'altro relativo alla generazione del DBContext; se invece stai utilizzando EF 5 con VS2010, devi aggiungere i template che ti interessano.

    Relativamente alla difficoltà nella modifica del Template, considera che parliamo semplicemente di un file che è composto da un mix di commenti di testo, codice, e direttive di elaborazione; nel tuo caso si tratta di inserire una funzione che si occupi di inserire la stringa dell'attributo o metadato che vuoi riportare sopra la firma di ogni proprietà, quindi individuare la direttiva di elaborazione delle proprietà e inserire l'invocazione della tua funzione.

    Riguardo all'articolo che hai trovato, può essere una strada percorribile, ma considera che con quell'approccio stai andando a scrivere nuovamente tutte le firme delle proprietà e le firme delle classi aggiungendo a mano gli attributi o metadati che ti interessano, a quel punto si va praticamente a nullare il tempo risparmiato grazie alla generazione automatica del codice delle classi.

    Pierluigi

    • Contrassegnato come risposta Marco Migani mercoledì 9 ottobre 2013 20:24
    mercoledì 9 ottobre 2013 09:47

Tutte le risposte

  • Ciao Marco,

    da quanto descrivi, effettivamente si, sbagli qualcosa; non è corretto modificare, manualmente, i file delle classi auto generati da EF.

    Entity Framework si poggia su una tecnologia chiamata "T4 Templates" per la generazione automatica del codice delle classi e ogni volta che tu apporti delle modifiche al tuo EDMX, o anche semplicemente lo salvi, il codice contenuto all'interno del Template viene rieseguito da Visual Studio e quindi i file auto generati vengono, scusa il gioco di parole, generati nuovamente.

    Quindi per decorare con attributi il codice auto generato, nel tuo caso le proprietà, devi modificare il Template di generazione delle classi aggiungendo anche il codice per la generazione automatica degli attributi.

    Ti riporto per semplicità due link, il primo un articolo, forse un po' vecchiotto, ma che comunque potrà aiutarti a capire la tecnologia, il secondo ti porta proprio al Get Started with Entity Framework presente su msdn:

    T4 Templates and the Entity Framework: http://msdn.microsoft.com/en-us/data/gg558520.aspx

    EF Designer Code Generation Templates: http://msdn.microsoft.com/en-us/data/jj613116.aspx

    Riguardo alla modifica manuale del model, se hai generato il tuo modello partendo dal DB, sarebbe meglio, perlomeno fin quando non acquisti confidenza con EF, che tu apportassi le tue modifiche al DB e quindi le propagassi fino al EDMX aggiornando tramite il wizard messo a disposizione.

    Pierluigi

    • Contrassegnato come risposta Marco Migani martedì 8 ottobre 2013 14:33
    • Contrassegno come risposta annullato Marco Migani martedì 8 ottobre 2013 15:12
    martedì 8 ottobre 2013 12:30
  • Grazie mille Pierluigi!

    Solo che modificare il Template di generazione delle classi nel mio caso non mi sembra molto facile: come aggiungo il Template per ora ottengo una miriade di errori...

    ne ho provati due:
     EF 5.x EntityObject Generator
     EF 5.x Self Tracking Entity Generator

    magari riproverò con calma partendo da una situazione più semplice.
    Nel frattempo ho visto questa tecnica che mi sembra abbastanza semplice, che promette di fare la stessa cosa,

    codeproject/Articles/148486/Adding-Metadata-to-Entities-in-The-Data-Model
     (bisogna aggiungere http e  www prima di codeproject e .com dopo codeproject perchè il forum non mi permette ancora di inserire dei link)

    ti sembra una via percorribile?
     Marco

    martedì 8 ottobre 2013 15:01
  • Ciao Marco,

    probabilmente non ci siamo capiti, dal titolo del primo post sembrava che tu stessi utilizzando EF 4, ma da quanto scrivi in questo secondo si evince che tu stai utilizzando EF 5; sarebbe anche utile sapere che versione di VS stai utilizzando. Se stai utilizzando EF 5 con VS2012, non devi aggiungere nessun Template, questo perché li aggiunge già di defaut, infatti se vai a vedere il contenuto del ramo del file EDMX nel Solution Explorer, troverai già due file con estenzione tt uno relativo alla generazione delle POCO Entities e l'altro relativo alla generazione del DBContext; se invece stai utilizzando EF 5 con VS2010, devi aggiungere i template che ti interessano.

    Relativamente alla difficoltà nella modifica del Template, considera che parliamo semplicemente di un file che è composto da un mix di commenti di testo, codice, e direttive di elaborazione; nel tuo caso si tratta di inserire una funzione che si occupi di inserire la stringa dell'attributo o metadato che vuoi riportare sopra la firma di ogni proprietà, quindi individuare la direttiva di elaborazione delle proprietà e inserire l'invocazione della tua funzione.

    Riguardo all'articolo che hai trovato, può essere una strada percorribile, ma considera che con quell'approccio stai andando a scrivere nuovamente tutte le firme delle proprietà e le firme delle classi aggiungendo a mano gli attributi o metadati che ti interessano, a quel punto si va praticamente a nullare il tempo risparmiato grazie alla generazione automatica del codice delle classi.

    Pierluigi

    • Contrassegnato come risposta Marco Migani mercoledì 9 ottobre 2013 20:24
    mercoledì 9 ottobre 2013 09:47
  • ...

    Riguardo all'articolo che hai trovato, può essere una strada percorribile, ma considera che con quell'approccio stai andando a scrivere nuovamente tutte le firme delle proprietà e le firme delle classi aggiungendo a mano gli attributi o metadati che ti interessano, a quel punto si va praticamente a nullare il tempo risparmiato grazie alla generazione automatica del codice delle classi.

    Pierluigi

    Ciao,

    punti di vista... :) con il controllo completo sul codice fai esattamente ciò che vuoi, e spesso questo significa non perdere tempo a cercare potenziali workaround per tante cose che ti possono capitare... Parere personale eh! ;)

    Inoltre se proprio non vuole scriverle a mano può sempre farsi creare le classi da VS con Database First per poi prendere i file creati ed usare quelli, in seguito può cambiare l'approccio con Code First mantenendo i file creati, in questo modo VS ti scrive le property e tu non devi scriverle a mano, ma poi nel loro utilizzo con Code First sei libero di fare ciò che vuoi...

    mercoledì 9 ottobre 2013 19:22
  • Grazie assai a Pierluigi e U 235!

    Per Pierluigi: sì, scusa, ho confuso la versione di MVC con quella di EF che è la 5.

    Ti chiederei un'ultima cosa, ma solo se puoi...

    potresti postarmi un piccolo snippet, un esempio di codice su come decodare una proprità della classe generata (POCO Entity) con l'attributo

    <Display(Name:="Nome visualizzato")>

    io mi limiterei a scriverlo così com'è sulla proprietà

    <Display(Name:="Nome visualizzato")>
    Pubblic Property NomeProprieta As String

    ma ovviamente, come abbiamo visto, è l'approccio sbagliato...

    Marco


    mercoledì 9 ottobre 2013 20:35
  • Ciao Marco,

    non è semplice perché non conosco la logica che vuoi applicare alla nominazione, quindi prendilo proprio come un esempio che poi tu dovrai finire di elaborare.

    public string PropertyMetaDataDisplayName(EdmProperty edmProperty)
    {
        //Qui devi inserire la tua logica di nominazione
        //Per esempio partendo dal nome originale della proprietà
        var propertyName = edmProperty.Name
        
        //E poi elaborandolo secondo la logica che vuoi applicare
        var displayName = .....
    
        //Una volta definito il nome che vuoi visualizzare
        return string.Format(
            CultureInfo.InvariantCulture,
    	"<Display(Name:=\"{0}\")>",
    	displayName);
    }

    Questa funzione la puoi inserire nel file tt subito prima della funzione che definisce e genera le firme delle proprietà, per semplificarti la ricerca ti virgoletto la firma della funzione che devi cercare "public string Property(EdmProperty edmProperty)".

    Come ti dicevo nel post precedente una volta definita e inserita la funzione che definisce e genera il tuo attributo, devi inserire l'invocazione della funzione tra le direttive di generazione delle proprietà, la direttiva che devi cercare è la seguente "<#=codeStringGenerator.Property(edmProperty)#>" e la direttiva che devi aggiungere subito prima è "<#=codeStringGenerator.PropertyMetaDataDisplayName(edmProperty)#>".

    Arrivati a questo punto tieni presente che la logica di generazione considera ed elabora le proprietà suddivise in SimpleProperties per le proprietà semplici e ComplexProperties per le proprietà di navigazione, le NavigationProperty, quello che avrai inserito, arrivato a questo punto, sarà per le SimpleProperty se ti dovesse interessare farlo anche per le NavigationProperty non dovrai far altro che replicare il tutto con le dovute semplici modifiche anche per le Navigation, considera che sia le funzioni di generazione, sia le direttive di invocazione si trovano successive a quelle che hai inserito.

    Una volta terminato, selezionando con il tasto destro del mouse il file tt nel Solution Explorer, dal menù di popup puoi eseguire il debug passo passo di quanto fatto selezionando "Debug T4 Template", naturalmente prima dovrai inserire gli opportuni punti di interruzione dove ti interessa.

    Spero di essere stato sufficientemente chiaro ed esaustivo

    Pierluigi

    • Contrassegnato come risposta Marco Migani giovedì 10 ottobre 2013 13:44
    giovedì 10 ottobre 2013 11:16
  • thank you Pierluigi!
    giovedì 10 ottobre 2013 13:45