EF code-first: aggiungere un nuovo campo

domenica 16 novembre 2014 - 00.02
Tag Elenco Tags  C#

Gemini Profilo | Expert

Ciao a tutti
alcune domande su EF code-first.
C'è un modo, quando definisco una classe, di indicare il numero di caratteri di un campo nel database? Per esempio, inserisco una classe una proprietà di tipo int, ma nel db mi server avere un bigint o definisco una proprietà di tipo string e nel db voglio che sia un varchar(5).

Se dopo un pò di tempo voglio aggiungere un nuovo campo nel db, mi basta semplicemente aggiungere la proprietà alla classe?
Ho trovato un tutorial che dice di aggiungere questo al global.asax:
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<EmployeeDBContext>());
ma a quanto ho capito mi ricrea il db e la mia paura è che cancelli tutto.
Grazie mille

0v3rCl0ck Profilo | Guru

>Ciao a tutti
>alcune domande su EF code-first.
>C'è un modo, quando definisco una classe, di indicare il numero
>di caratteri di un campo nel database? Per esempio, inserisco
>una classe una proprietà di tipo int, ma nel db mi server avere
>un bigint o definisco una proprietà di tipo string e nel db voglio
>che sia un varchar(5).

se vuoi un mapping con un bigint, usa semplicemente una proprietà di tipo long (64bit), il più delle volte è sufficiente trovare il tipo di dato corrispondente in tipologia (numerico, string) e dimensione (16bit, 32bit, 64bit), perchè tu abbia un map automatico, come per long e bigint entrambi numberico con segno a 64bit (8 bytes).

Per le stringhe invece è possibile specificare la lunghezza massima, o attraverso fluent API oppure Data Annotation:

Fluent API (http://msdn.microsoft.com/en-us/data/jj591617):
public class MyDbContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(t => t.Title) .HasMaxLength(255); modelBuilder.Entity<Blog>() .Property(t => t.BloggerName) .HasMaxLength(50); } } public class Blog { public int Id { get; set; } public string Title { get; set; } public string BloggerName { get; set; } }

Data annotation (http://msdn.microsoft.com/en-us/data/jj591583):
public class Blog { public int Id { get; set; } [MaxLength(255)] public string Title { get; set; } [MaxLength(50)] public string BloggerName { get; set; } }

io preferisco sempre la fluent api, perchè mi permette di disaccoppiare la modellazione dalla configurazione del mapping EF. Inoltre ti consiglio di utilizzare un approccio a classi di configurazione separate per entità, per evitare di avere troppo casino nel metodo OnModelCreating, sfruttando la collezione modelBuilder.Configurations.Add(...) e implementando le tue EntityTypeConfiguration: http://odetocode.com/blogs/scott/archive/2011/11/28/composing-entity-framework-fluent-configurations.aspx

public class ProductConfiguration : EntityTypeConfiguration<Product> { public ProductConfiguration() { ToTable("products"); Property(p => p.Name).HasMaxLength(255); Property(p => p.Version) .IsConcurrencyToken() .IsRowVersion(); } } protected override void OnModelCreating( DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new ProductConfiguration()); // ... and so on, for each configuration class base.OnModelCreating(modelBuilder); }

>
>Se dopo un pò di tempo voglio aggiungere un nuovo campo nel db,
>mi basta semplicemente aggiungere la proprietà alla classe?

si, ma devi approfondire l'argomento "Code-First Migrations", se vuoi che il database si evolva automaticamente: http://msdn.microsoft.com/en-us/data/jj591621

>Ho trovato un tutorial che dice di aggiungere questo al global.asax:
>Database.SetInitializer(new DropCreateDatabaseIfModelChanges<EmployeeDBContext>());
>ma a quanto ho capito mi ricrea il db e la mia paura è che cancelli
>tutto.

Certo, questo cancella assolutamente tutto, quindi sostanzialmente NON DEVE MAI ESSERE UTILIZZATO IN PRODUZIONE, a meno che tu non voglia davvero buttare via tutti i dati al cambio del modello dati. Quelle sono facility per aumentare la produttività dello sviluppatore durante la fase di sviluppo, per tutto il resto, c'è "migrations" (http://msdn.microsoft.com/en-us/data/jj591621).


>Grazie mille

di niente


Michael Denny | Microsoft Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.net
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

0v3rCl0ck Profilo | Guru

Se non sei troppo lontano, e se si liberano posti (perchè ora è full), c'è l'evento free Sql Saturday 2014 a Parma (http://www.sqlsaturday.com/355/eventhome.aspx), dove terrò una sessione proprio su Entity Framework 6 (http://www.sqlsaturday.com/viewsession.aspx?sat=355&sessionid=25373), dove cercherò di fare vedere un po' tutte queste cose rapidamente, tra cui anche la Migrations. Se avresti l'intenzione di venire, prova comunque ad iscriverti, dovrebbe metterti in waiting list, sperando che si liberi un posto.


Michael Denny | Microsoft Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.net
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

Gemini Profilo | Expert

Grazie per l'aiuto
Mi dispiace, ma abito molto lontano da Parma.

Un'ultima domanda sull'organizzazione delle classi. Fino ad oggi ho organizzato le classi in questo modo: definivo le proprietà e i metodi, metodi che mi permettevo di recuperare i dati dal db o di eseguire alcune operazioni.
Ora, se utilizzo EF continuo ad utilizzare questa organizzazione contrassegnando come 'not mapped' le proprietà che non voglio salvare nel db? O definisco le proprietà in una classe e i metodi in un'altra facendo ereditare a quest'ultima le proprietà? In quest'ultimo caso tengo separato proprietà utilizzate per creare il db e i metodi.
Grazie

0v3rCl0ck Profilo | Guru

riesci a postare le classi che utilizzi? così da vedere se posso instradarti al meglio


Michael Denny | Microsoft Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.net
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

Gemini Profilo | Expert

Ciao
ecco come organizzo le classi ora:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Routing; using System.Web; public class tipoCategoria { public tipoCategoria() { } public string ID { get; set; } public string FkPadre { get; set; } public string Categoria { get; set; } public string Tipologia { get; set; } public string Status { get; set; } public string RealUrl { get { return Routing.RewritelUrl(Categoria.ToLower(), "-"); } } public string Pagina(string tipo) { string url = string.Empty; switch (tipo) { case "corso": url = Routing.PageRouteCorsiCategorie(ID, RealUrl); break; case "master": url = Routing.PageRouteMasterCategorie(ID, RealUrl); break; case "universita": url = Routing.PageRouteCategorieCorsiUni(ID, RealUrl); break; } return url; } }

Stavo pensando di definire le proprietà solo in tipoClasse, far ereditare a Classe tipoClasse e mappare EF su tipoClasse. Perchè come puoi vedere in CorsoCategoria, utilizzo List<tipoCategoria> e se seguo la logica di EF dovrei fare List<CorsoCategoria>.

Ogni suggerimento su come migliore il codice sono bel graditi. Mi piacerebbe trovare un esempio o un progetto reale che utilizza EF code-first per capire come organizzare le classi e il codice. Gli esempi dei tutorial e degli articoli sono troppo semplici e non corrispondono all'idea che ho di organizzazione del codice.
Grazie

0v3rCl0ck Profilo | Guru

scusami, ma è un po' lungo spiegarti da capo un organizzazione multi-layer di un progetto, in generale ci sono tanti esempi in giro, l'unico consiglio che posso darti è di separare bene l'accesso ai dati, da quello che è la UI, anche come modellazione a classi, cioè per l'entity e per i tuoi dati di dominio utilizza un modello pulito e assolutamente legato ai dati, senza metodi o proprietà che servono solo alla UI, poi per l'interfaccia ti crei i così detti ViewModel, che sono classi utilizzate per la visualizzazione dei dati, e si, devi copiare gli oggetti che ti arrivano da entity, negli oggetti ViewModel. Questo non è sempre obbligatorio, se gli oggetti di entity saranno sufficienti a popolare la UI bene così, ma se per caso devi aggiungere una proprietà o strutturare diversamente i dati solo per la UI, non dovresti toccare gli oggetti di dominio (classi entity EF), ma crearti appunti classi nuove ad-hoc per la UI.

Poi ho trovato questi sample, che giocano un po' con tutte le tecnologie .net, compreso EF, applicando una strutturazione multi-layer: http://layersample.codeplex.com/


Michael Denny | Microsoft Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.net
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2025
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5