Entity Framework
Code First - Fluent API
Ricerca…
Osservazioni
Esistono due modi generali per specificare come HOW Entity Framework mapperà le classi POCO alle tabelle, alle colonne, ecc. Del database: Annotazioni dei dati e API Fluent .
Sebbene le annotazioni dei dati siano semplici da leggere e comprendere, mancano alcune funzionalità, come la specifica del comportamento "Cascata all'eliminazione" per un'entità. L'API Fluent d'altra parte è un po 'più complessa da usare, ma offre un set di funzionalità molto più avanzato.
Modelli di mappatura
EntityFramewok Fluent API è un modo potente ed elegante per mappare i tuoi modelli di dominio code-first al database sottostante. Questo può anche essere usato con code-first con il database esistente . Sono disponibili due opzioni quando si utilizza l' API Fluent : è possibile mappare direttamente i modelli sul metodo OnModelCreating oppure è possibile creare classi di mapping che ereditano da EntityTypeConfiguration e quindi aggiungere tali modelli a modelBuilder sul metodo OnModelCreating . La seconda opzione è quella che preferisco e mostrerò un esempio.
Fase 1: creare un modello.
public class Employee
{
public int Id { get; set; }
public string Surname { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public short Age { get; set; }
public decimal MonthlySalary { get; set; }
public string FullName
{
get
{
return $"{Surname} {FirstName} {LastName}";
}
}
}
Passo 2: crea una classe mapper
public class EmployeeMap
: EntityTypeConfiguration<Employee>
{
public EmployeeMap()
{
// Primary key
this.HasKey(m => m.Id);
this.Property(m => m.Id)
.HasColumnType("int")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
// Properties
this.Property(m => m.Surname)
.HasMaxLength(50);
this.Property(m => m.FirstName)
.IsRequired()
.HasMaxLength(50);
this.Property(m => m.LastName)
.HasMaxLength(50);
this.Property(m => m.Age)
.HasColumnType("smallint");
this.Property(m => m.MonthlySalary)
.HasColumnType("number")
.HasPrecision(14, 5);
this.Ignore(m => m.FullName);
// Table & column mappings
this.ToTable("TABLE_NAME", "SCHEMA_NAME");
this.Property(m => m.Id).HasColumnName("ID");
this.Property(m => m.Surname).HasColumnName("SURNAME");
this.Property(m => m.FirstName).HasColumnName("FIRST_NAME");
this.Property(m => m.LastName).HasColumnName("LAST_NAME");
this.Property(m => m.Age).HasColumnName("AGE");
this.Property(m => m.MonthlySalary).HasColumnName("MONTHLY_SALARY");
}
}
Cerchiamo di spiegare i mapping:
- HasKey : definisce la chiave primaria. È anche possibile utilizzare chiavi primarie composte . Ad esempio: this.HasKey (m => new {m.DepartmentId, m.PositionId}) .
- Proprietà : ci consente di configurare le proprietà del modello.
- HasColumnType : specifica il tipo di colonna del livello del database. Si noti che, può essere diverso per diversi database come Oracle e MS SQL.
- HasDatabaseGeneratedOption - specifica se la proprietà è calcolata a livello di database. I PK numerici sono DatabaseGeneratedOption.Identity per impostazione predefinita, è necessario specificare DatabaseGeneratedOption.None se non si desidera che siano tali.
- HasMaxLength : limita la lunghezza della stringa.
- IsRequired : contrassegna la proprietà come requiered.
- HasPrecision : ci consente di specificare la precisione per i decimali.
- Ignora : ignora completamente la proprietà e non la associa al database. Abbiamo ignorato FullName, perché non vogliamo questa colonna al nostro tavolo.
- ToTable : specifica il nome della tabella e il nome dello schema (facoltativo) per il modello.
- HasColumnName : associa la proprietà al nome della colonna. Questo non è necessario quando i nomi delle proprietà e i nomi delle colonne sono identici.
Passaggio 3: aggiunta della classe di mapping alle configurazioni.
Dobbiamo dire a EntityFramework di usare la nostra classe mapper. Per fare ciò, dobbiamo aggiungerlo a modelBuilder.Configurations sul metodo OnModelCreating :
public class DbContext()
: base("Name=DbContext")
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new EmployeeMap());
}
}
E questo è tutto. Siamo pronti per partire.
Chiave primaria
Utilizzando il metodo .HasKey (), una proprietà può essere configurata esplicitamente come chiave primaria dell'entità.
using System.Data.Entity;
// ..
public class PersonContext : DbContext
{
// ..
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ..
modelBuilder.Entity<Person>().HasKey(p => p.PersonKey);
}
}
Chiave primaria composita
Utilizzando il metodo .HasKey (), un insieme di proprietà può essere configurato esplicitamente come chiave primaria composita dell'entità.
using System.Data.Entity;
// ..
public class PersonContext : DbContext
{
// ..
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ..
modelBuilder.Entity<Person>().HasKey(p => new { p.FirstName, p.LastName });
}
}
Lunghezza massima
Utilizzando il metodo .HasMaxLength (), il numero massimo di caratteri può essere configurato per una proprietà.
using System.Data.Entity;
// ..
public class PersonContext : DbContext
{
// ..
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ..
modelBuilder.Entity<Person>()
.Property(t => t.Name)
.HasMaxLength(100);
}
}
La colonna risultante con la lunghezza della colonna specificata:
Proprietà richieste (NOT NULL)
Usando il metodo .IsRequired (), le proprietà possono essere specificate come obbligatorie, il che significa che la colonna avrà un vincolo NOT NULL.
using System.Data.Entity;
// ..
public class PersonContext : DbContext
{
// ..
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ..
modelBuilder.Entity<Person>()
.Property(t => t.Name)
.IsRequired();
}
}
La colonna risultante con il vincolo NOT NULL:
Esplicita denominazione di chiave esterna
Quando esiste una proprietà di navigazione su un modello, Entity Framework creerà automaticamente una colonna Chiave esterna. Se un determinato nome di chiave esterna è desiderato ma non è contenuto come una proprietà nel modello, può essere impostato in modo esplicito utilizzando l'API Fluent. Utilizzando il metodo Map
mentre si stabilisce la relazione Foreign Key, è possibile utilizzare qualsiasi nome univoco per le chiavi esterne.
public class Company
{
public int Id { get; set; }
}
public class Employee
{
property int Id { get; set; }
property Company Employer { get; set; }
}
public class EmployeeContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasRequired(x => x.Employer)
.WithRequiredDependent()
.Map(m => m.MapKey("EmployerId"));
}
}
Dopo aver specificato la relazione, il metodo Map
consente di impostare esplicitamente il nome della chiave MapKey
eseguendo MapKey
. In questo esempio, ciò che sarebbe risultato in un nome di colonna di Employer_Id è ora EmployerId.