Upload
martino-bordin
View
423
Download
10
Embed Size (px)
DESCRIPTION
EF Code First e NH, due O/RM a confronto - Un overview su due diverse tecnologie di accesso ai dati
Citation preview
EF CODE FIRST E NH, DUE O/RM A CONFRONTOUn overview su due diverse tecnologie di accesso ai dati
MARTINO BORDINPIETRO LIBRO http://efcfvsnh3.codeplex.com
Agenda
Mapping, Configuration e creazione del DB
Query API CUD Validazione
Entity Framework
Configuration e Mapping
Strategie di utilizzo di Entity Framework Database First Model First Code First
Overview sulla versione CTP5 di EF. Solo per Code First ? NO!
CTP contiene una versione di preview (non definitiva!) delle nuove API che permettono una maggiore produttività con EF: DbContext
DdContext (1)
CustomClass: DbContext {...} ObjectContext Wrapper (vedremo come
ricavare l’ObjectContext corrente) Dal costruttore dipende:
Connessione al Database Code First\ Database First\ Model First Opzioni avanzate
DbContext (2)
Code First Connection by convention Connection by convention + database
name By connection string Database\Model First, questioni di provider
E altro ancora ...
Inizializzazione del db
Possibili strategie: Cancella e crea (utile in fase di test):
DbDatabase.SetInitializer<Db>(new DropCreateDatabaseAlways<Db>());
Crea se non esiste:DbDatabase.SetInitializer<Db>(new CreateDatabaseIfNotExists<Db>());
Cancella e crea se il modello cambia (!!!):DbDatabase.SetInitializer<Db>(new DropCreateDatabaseIfModelChanges<Db>());
Custom:DbDatabase.SetInitializer<Db>(new DbCustomInitializerStrategy<Db>());
DEMO
Mapping (1)
Code First Mapping by Convention (Strategia più semplice) Overriding conventions
Attributi Max Length Column Name Table Name ...
Fluent API
Mapping (2)
Fluent API Stesse funzioni di mapping degli attributi Scenari di mapping più complessi (non
possibili con attributi) Entity Splitting (1 Entity N Table) Configurazione di gerarchie di ereditarietà:
Table per class Table per class hierarchy Table per concrete class
Table Splitting (1 Table N Entity) Override OnModelCreating
DEMO
Query
Caricamento dati, novità: Find
DbContext.Developers.Find(1) Include (Tipizzato)
from dev in db.Developers.Include (s=>s.Skills ) where dev.Surname =="Libro"
Load (Carica i dati in memoria senza restituirli) DbContext.Developers.Load()
AsNoTracking (migliori performance) DbContext.Developers.AsNoTracking ()
LINQ (from d in db.Developers select d).FirstOrDefault();
SqlQuery DbContext.Developers.SqlQuery(query, new object[] { }); //Tracking. DbContext.Database.SqlQuery<Developer>(); //No
tracking.
Validazione (1)
Perché ‘Validare ?’ Dati corretti Risparmiare trip sul server ( ad esempio -
transazioni SQL Azure) In EF
Abilitata per default Utilizza attributi
(DataAnnotations.ValidationAttribute), eventualmente Custom
Validazione automatica dei Complex Type Supporta l’interfaccia IValidatableObject Attributi su Navigation Properties e Collection
(validità della proprietà e non degli elementi)
Validazione (2)
Perché non usare ? System.ComponentModel.DataAnnotations.Validator
In EF, validazione eseguita: Durante il tentativo di persistenza dei dati On-demand per singola entità On-demand per singola proprietà
Se la validazione non è effettuata con successo: DbEntityValidationException (EntityValidationErrors)
DbEntityValidationResult (ValidationErrors) ValidationError
DEMO
Proprietà (1)
Due valori per ogni proprietà: Current Value (get/set)
entity.Name Context.Entry(entity).Property(n=>n.name).Curre
ntValue
Original Value (get/set) Context.Entry(entity).Property(n=>name).Origina
lValue
Lo stesso discorso vale per le proprietà non mappate
Proprietà (2)
Verificare proprietà modificate: Context.Entry(entity).Property(n=>n.name).
IsModified (Get\Set) Forza Update durante il SaveChanges()
anche se Original Value e Current Value coincidono
Leggere Current, Original e Database Values: Context.Entry(entity).CurrentValues() Context.Entry(entity).OriginalValues() Context.Entry(entity).GetDatabaseValues()
Proprietà (3)
Original e Current Values da un altro oggetto: Consideriamo il nostro DTO Developer:
new employeeDTO {Name=‘Pippo’ , Surname=‘Franco’};
Il DTO viene utilizzato da Service Layer per la comunicazione tra strati
Valorizzare la entity da modificare Context.Entry(entity).CurrentValues.SetValues(e
mployeeDTO)
Concorrenza
Concorrenza (ottimistica): Specifichiamo le proprietà interessate
Attributo [ConcurrencyCheck] Due possibili patterns:
Store Wins Utilizziamo il metodo 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 incogruenze)
DEMO
NHibernate
Agenda
Mapping, Configuration e creazione del DB
Query API CUD, Session & Transaction Validazione
Mapping
XML FluentNH ConfORM
Mapping con XML
[NomeTabella].hbm.xml come «Embedded Resource»
XSD per validare l’xml prodotto e per l’intellisense di VS
Mapping con FluentNH
Classi derivanti da (Sub)ClassMap<Entity>
Si invocano metodi quali: Id Map HasMany HasManyToMany Component
DEMO
Mapping con ConfORM
Creazione di mapping convention-based. ObjectRelationalMapper e Mapper
per ottenere un HbmMapping
Configuration
app|web.config o hibernate.cfg.xml Codice FluentNH ConfORM
Configurazione con app|web.config o hibernate.cfg.xml
Sezione hibernate-configuration in app|web.config
o File hibernate.cfg.xml
Metodo Configuration().Configure()
Configurazione via codice
Configuration mediante fluent interface:
new Configuration().DatabaseIntegration(db => { db.Dialect<MsSql2008Dialect>(); db.ConnectionStringName = «myDB»;
}).AddAssembly(«MappingAssembly»);
Configurazione con FluentNH Configuration mediante l’oggetto Fluently:
Fluently.Configure().Database(MsSqlConfiguraiton.MsSQL2008.ConnectionString(c =>
c.FromConnectionStringWithKey(«myDB»)).Mappings(m =>
m.FluentMappings.AddFromAssembly(..)).BuildConfiguration();
DEMO
Configurazione con ConfORM Si crea la Configuration via codice o
FluentNH, e si chiama il metodo config.AddDeserializedMapping(HbmMapping)
Creazione del DB
Schema Export Setting nella configurazione
Creazione del DB con Schema Export
Visulizzazione script sulla console Scrittura script su file Esecuzione
new SchemaExport(config)
DEMO
Creazione del DB con setting nella configurazione
hbm2ddl.auto:update, create, create-drop, validate.
Con FluentNH: ExposeConfiguration(cfg => cfg.SetProperty("hbm2ddl.auto", " create-drop "));
Query API
HQL Criteria QueryOver Linq to Nhibernate SQL
Query con HQL
Sintassi simile a SQL String-based Hqladdin.codeplex.com per Intellisense
session
.CreateQuery("select a from Developer a inner join a.Skills c where c.Description = :skillDescription")
.SetString("skillDescription", "LINQ")
.List<Developer>();
Query con Criteria
Permette di costruire la Query dinamiche I campi sono espressi mediante stringhesession
.CreateCriteria<Developer>()
.CreateCriteria("Skills", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(Restrictions.Eq("Description", "LINQ"))
.List<Developer>();
Query con QueryOver
Basata su Criteria, ma è strong-type e «fluent»
Introdotta con NH3session
.QueryOver<Developer>()
.Inner
.JoinQueryOver<Skill>(d => d.Skills)
.Where(s => s.Description == "LINQ").List();
Query con Linq to NHibernate
Permette di sfruttare Linq per effettuare query OO
session.Query<Developer>()
.Where(d => d.Skills.Any(s => s.Description == "LINQ"))
.ToList();
Query con SQL
Query SQL scritta su un file hbm.xml embedded.
session.CreateSQLQuery(«select count(*) from
competenza») .UniqueResult()
DEMO
Session e Transaction
Unit of Work
Mantiene la lista di oggetti coinvolti in una business transaction(*)
Coordina la persistenza delle modifiche Gestisce la risoluzione della concorrenza.
(*)Change tracking
Creazione Session
SessionFactory.OpenSession(); La creazione della SessionFactory è
«onerosa» La creazione della Session è veloce
Session API
Load/Get per ottenere un oggetto data la sua chiave Save/Update/SaveOrUpdate marca un oggetto
come da aggiungere/aggiornare(non lo salva sul database)
Delete marca un oggetto come da eliminare Evict sgancia un oggetto dalla sessione Merge (ri)aggancia un oggetto detached alla
sessione, in maniera da poterlo persistere correttamente.
Refresh (ri)carica un oggetto persistente dal database.
Flush persiste le modifiche sul database.
Transaction
Session TransactionScope
Transaction con Session
Si crea una Transaction con session.BeginTransaction Si può eseguire il Commit o il Rollback
var transaction = session.BeginTransaction();try{ session.Save(developer); transaction.Commit();}catch (Exception){ transaction.Rollback();}
Transaction con Transaction Scope Permette di creare transazioni distribuite su più sistemi NON sostituisce la transazione di NH using (var scope = new TransactionScope()) { using (var session = sessionFactory.OpenSession()) using (var transaction = session.BeginTransaction()) { // do what you need to do..
session.Save(developer); transaction.Commit(); } scope.Complete(); }
Concorrenza
Concorrenza (ottimistica): Version TimeStamp Dirty-Checkin
DEMO
Validazione con Nhibernate.Validator
Attributi, file nhv.xml, fluent new
ValidatorEngine() .GetInvalidValues(customer)
Ha 2 event listener per PreInsertEvent e PreUpdateEvent
InvalidStateException con un array di InvalidValue
CONCLUSIONI
Riferimenti
Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog
Martino Bordin http://blogs.ugidotnet.org/martinobordin
Entity Framework – ADO.NET Team Blog http://blogs.msdn.com/b/adonet
NHIbernate http://nhforge.org/Default.aspx