advanced ef code first 5.0 - ef@work
DESCRIPTION
Sessione "Advanced ef code first 5.0" tenuta da Luca Cestola all'evento EF@Work di DomusDotNet (http://www.domusdotnet.org/eventi/efatwork.aspx) del 5 Luglio 2013TRANSCRIPT
@EF@Wor
k
@EF@Work
EF 5.0 Code First
Luca [email protected]
http://it.linkedin.com/pub/luca-cestola/
9/652/122
@EF@Wor
k
• Configuration & Mapping• Validazione• Entity, oggetti «transient»• Query Custom• Concorrenza
Agenda
@EF@Wor
k
• L’origine di tutto: la classe DbContext• I passi minimi nell’approccio Code First:• Costruire le classi che definiscono l’object
Model as Data Model• Costruire una classe derivata da DbContext• Esporre proprietà System.Data.Entity.DBSet<>
per ognuna delle classi dell’Object Model che si vuole rendere direttamente accessibili
• Se ci basiamo solo sulle convezioni: nient’altro.
Configuration & Mapping
@EF@Wor
k
• Convezioni• Nome database e stringa di connessione• Di default: LocalDb o SQLEXPRESS, Full
Qualified Type Name del DbContext derivato
• Type Discovery• Tipi definiti nei DbSet<>• Tipi referenziati dai DbSet (anche se in assembly
differenti)
Configuration & MappingIn assenza di una ConnectionString specifica viene utilizzato localDb o SQLExpress. Nel caso in cui siano installati entrambi, viene privilegiato SQLExpress. Default namespace CarRental.EF5.DataAccess { public class CarRentalDB : DbContext { ... } } Nome database “CarRental.EF5.DataAccess.CarRentalDB”
Nome specifico namespace CarRental.EF5.DataAccess { public class CarRentalDB : DbContext : base("CarRentalDatabase") { ... } } Nome database “CarRentalDatabase”
Connection string <configuration> <connectionStrings> <add name="CarRentalDatabase" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=CarRental.sdf"/> </connectionStrings> </configuration>
namespace CarRental.EF5.DataAccess { public class CarRentalDB : DbContext : base("CarRentalDatabase") { ... namespace CarRental.EF5.DataAccess { public class CarRentalDB : DbContext : base("name=CarRentalDatabase") { ... namespace CarRental.EF5.DataAccess { public class CarRentalDB : DbContext : base("<connection string SQLServer> ") { ...
namespace CarRental.EF5.DataAccess { public class CarRentalDB : DbContext { public DbSet<Domain.Car> Cars { get; set; } public DbSet<Domain.Optional> Optionals { get; set; } public DbSet<Domain.Customer> Customers { get; set; } public DbSet<Domain.Rent> Rent { get; set; } } }
@EF@Wor
k
• Convenzioni• Nomi delle tabelle (Plurale basato su grammatica inglese)• Nomi delle colonne (nome della property)• Chiave primaria (property «Id» o «ClasseId», identity se int o
guid)• Navigation properties• Proprietà che hanno per tipo un’altra entity
• Foreign Key• Proprietà con stesso tipo della PK a cui si riferiscono, con nome:
[NomeProprietà][NomePK][NomeClassePK][NomePK][NomePK]
• Tipi i tipi base (in EF5 anche enum, DbGeography e DbGeometry)
• Ecc… (http://msdn.microsoft.com/en-US/data/jj679962)
Configuration & Mapping
@EF@Wor
k
• Convenzioni• Complex type• Ogni classe referenziata nel model senza PK e non inclusa
in collection
• Tipi di relazioni• Sono relazioni tutte le property che fanno riferimento ad
un’altra entity
• Rimuovere le convenzioni• PluralizingTableNameConvention,
ComplexTypeDiscoveryConvention, ecc… (http://msdn.microsoft.com/en-us/
library/system.data.entity.modelconfiguration.conventions(v=vs.103).aspx)
• Custom Convention?• … in EF6!
Configuration & Mapping
DEMO
@EF@Wor
k
• Convezioni• Possiamo cambiarle ? Ovviamente si:• Utilizzando gli attributi del
System.ComponentModel.Annotations• Fluent API
Configuration & Mapping
@EF@Wor
k
• Convezioni• Annotation• Key• Column• MaxLength• ForeignKey• …
• L’utilizzo degli attributi può rendere «difficile» la lettura del codice della definizione del nostro modello dati.
Configuration & Mapping
DEMO
[MetadataType(typeof(CarMetadata))] public partial class Car { ... } public class CarMetadata { // I metadati sono associati a semplici Field // con lo stesso nome e tipo della Property che descrivono. [Required] [Display(Name = "Engine size (cc)")] public string EngineSize; ... }
@EF@Wor
k
•Fluent Api• Stesse funzionalità di mapping degli attributi• Necessarie per scenari di mapping più complessi (nel
99,99 % dei casi reali )• Entity Splitting (1 entità «spalmata» su N tabelle)• Gerarchie di Ereditarietà• Table per Class• Table per Class Hierarchy• Table per Concrete Class
• Table Splitting (1 tabella «spalmata» su N entità)• Configurazione & mapping concentrato in un solo punto:• Override OnModelCreating della classe DbContext• Relazioni: http://msdn.microsoft.com/en-us/data/jj591620
Configuration & Mapping
DEMO
@EF@Wor
kConfiguration & Mapping
DEMO
•Durante la fase di «mapping» possiamo utilizzare la collezione Configurations per:• Aggiungere nuove configurazioni a quelle già presenti• Classi derivate da• EntityTypeConfiguration<>• ComplexTypeConfiguration<>
•Per ogni istanza della classe derivata da DbContext, tramite la proprietà DbContext.Configuration possiamo impostare (abilitate per default):• AutoDetectChangesEnabled• LazyLoadingEnabled• ProxyCreationEnabled• ValidateOnSaveEnabled
@EF@Wor
k
• Inizializzazione del database• Cancella e crea in ogni caso• Database.SetInitializer<Db>(new
DropCreateDatabaseAlways<Db>());
• Crea se non esiste• Database.SetInitializer<Db>(new
CreateDatabaseIfNotExists<Db>());
• Cancella e crea se il modello cambia (Attenzione!)• Database.SetInitializer<Db>(new
DropCreateDatabaseIfModelChanges<Db>());
• Strategia Custom derivante da IDatabaseInitializer<>• Database.SetInitializer<Db>(new DbCustomDatabaseStrategy(
));
Configuration & Mapping
@EF@Wor
k
• Perché ‘Validare’ ?• Dati corretti (ma dai ?)• Risparmiare round trip sul server (SQL Azure)
• In EF 5• Abilitata per default• Utilizza attributi (DataAnnotations.ValidationAttribute)• Validazione automatica dei Complext Type• Supporta l’interfaccia IValidatableObject • IEnumerable<ValidationResult> Validate(ValidationContext
validationContext)• È buona pratica non alterare i dati durante una validazione
custom
Validazione
@EF@Wor
k
• Quando viene eseguita ?• Prima della persistenza dei dati (SaveChanges)• On-demand per singola entità• On-demand per singola proprietà
• Se la validazione non ha successo:• Exception DbEntityValidationException
(EntityValidationErrors)• DbEntityValidationResult (ValidationErrors)• ValidationError
Validazione
DEMO
@EF@Wor
k
• Per ogni proprietà di un’entità:• Current Value (get\set)• Context.Entry(entity).Property(n=>n.name).CurrentValue
• Original Value (get\set)• Context.Entry(entity).Property(n=>name).OriginalValue
• Verificare proprietà modificate:• Context.Entry(entity).Property(n=>n.name).IsModified
(Get\Set)• Forzare l’Update durante il SaveChanges() anche se
Original Value e Current Value coincidono• Current, Original e Database Values:• Context.Entry(entity).CurrentValues()• Context.Entry(entity).OriginalValues()• Context.Entry(entity).GetDatabaseValues()
Entity e oggetti «transient»
@EF@Wor
k
• Original e Current Values da un altro oggetto:• Consideriamo un DTO del tipo:• new Book {Title=‘Pippo’ , ISBN=‘Franco’};
• Il DTO viene utilizzato da Services Layer per la comunicazione tra strati dell’applicazione
• Valorizzare la entity da modificare:• Context.Entry(entity).CurrentValues.SetValues(d
to)
Entity e oggetti «transient»
DEMO
@EF@Wor
k
• Non c’è un supporto diretto al mapping di Stored Procedure se non tramite il designer, come ad esempio in Model First.
• Possiamo utilizzare alcuni «helper» di DbContext e DbSet
• DbContext.Cars.SqlQuery (con Tracking)
• DbContext.Database.SqlQuery<Cars> (No Tracking)
• DbContext.Database.ExecuteSqlCommand("EXECUTE [dbo].[GetAllCars]"); (No Tracking)
Query custom
DEMO
@EF@Wor
k
• Concorrenza (ottimistica):• Specifichiamo le proprietà interessate• Attributo [ConcurrencyCheck]
• Due possibili strategie:• Database wins:
Utilizziamo il metodo DbContext.Entity(istanza).Reload() per sovrascrivere i dati dell’entity con quelli presenti nel database
• Client Wins:Sostituiamo i valori originali dell’entity con quelli del database GetDatabaseValues() (eliminazione delle incongruenze)
Concorenza
DEMO
@EF@Wor
k
Entity Framework 5:http://msdn.microsoft.com/it-it/data/efBlog Entity Framework Design:http://blogs.msdn.com/b/efdesign Ado.Net Team Blog:http://blogs.msdn.com/b/adonetDomusDotNet:http://www.domusdotnet.org
Link utili
@EF@Wor
kGrazie agli sponsor