Usando l'api fluente, come faccio a mappare un tipo personalizzato come chiave primaria all'interno del mio metodo OnModelCreating della classe DbContext?
Usando EF Core sto provando a costruire un modello per l'entità follow.
public class Account
{
public AccountId AccountId { get; }
public string Name { get; set; }
private Account()
{
}
public Account(AccountId accountId, string name)
{
AccountId = accountId;
Name = name;
}
}
Dove la chiave primaria è l' AccountId
; il tipo è un oggetto con valore semplice come questo.
public class AccountId
{
public string Id { get; }
public AccountId(string accountId)
{
Id = accountId;
}
}
All'interno di OnModelCreating
, ho scoperto che non posso mappare l' AccountId
senza avere un campo di supporto. Così ho introdotto il campo di supporto _accountId
. Non voglio che AccountId abbia un setter.
public class Account
{
private string _accountId;
public AccountId AccountId { get { return new AccountId(_accountId); } }
public string Name { get; set; }
private Account()
{
}
public Account(AccountId accountId, string name)
{
_accountId = accountId.Id;
Name = name;
}
}
Ma non riesco ancora a capire come si specifica una proprietà con un campo di supporto che è anche la chiave primaria.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var account = modelBuilder.Entity<Account>();
account.ToTable("Accounts");
account.HasKey(x => x.AccountId);
account.Property(x => x.AccountId).HasField("_accountId");
}
OnModelCreating genera un'eccezione sulla linea della mappa delle proprietà ( account.Property(x => x.AccountId).HasField("_accountId");
). Affermando che proprietà e campo devono essere dello stesso tipo.
Come indicato, è possibile utilizzare una proprietà tipizzata personalizzata come chiave di entità sfruttando la funzione Conversione valore in EF Core 2.1
Quindi nel tuo esempio invece di mappare la proprietà a un campo di supporto, ora puoi definire una conversione personalizzata per questo in questo modo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
account.HasKey(x => x.AccountId);
account.Property(x => x.AccountId)
.HasConversion(
v => v.Id,
v => new AccountId(v));
}
Come descritto nella documentazione , anche una classe ValueConverter può essere implementata per rendere la conversione riutilizzabile e molti convertitori personalizzati sono forniti anche fuori dalla scatola.
Nota: è consigliabile implementare IComparable<T>
IComparable
e IComparable<T>
per la classe AccountId
personalizzata. Perché EF Core sembra ordinare le entità modificate in base alle loro chiavi internamente per le operazioni batch e si riceverà un'eccezione se la tua chiave non è paragonabile!