Using the fluent api, how do I map a custom type as the primary key within my OnModelCreating method of the DbContext class?
Using EF Core I'm trying to build a model for the follow entity.
public class Account
{
public AccountId AccountId { get; }
public string Name { get; set; }
private Account()
{
}
public Account(AccountId accountId, string name)
{
AccountId = accountId;
Name = name;
}
}
Where the primary key is the AccountId
; the type is a simple value object like this.
public class AccountId
{
public string Id { get; }
public AccountId(string accountId)
{
Id = accountId;
}
}
Within OnModelCreating
, I found I can't map the AccountId
without having a backing field. So I introduced the backing field _accountId
. I don't want the AccountId to have a 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;
}
}
But I still can't figure out how you specify a property with a backing field which is also the primary key.
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");
}
The OnModelCreating throws an exception on the property map line (account.Property(x => x.AccountId).HasField("_accountId");
).
Stating that property and field have to be the same type.
As pointed out, one can use a custom typed property as entity key by taking advantage of the Value Conversion feature in EF Core 2.1
So in your own example instead of mapping the property to a backing field, you can now define a custom conversion for it like this:
As described in the documentation, also a ValueConverter class can be implemented to make the conversion reusable and many custom converters are also provided out of the box.
Note: It's a good idea to implement
IComparable
andIComparable<T>
for your customAccountId
class. Because EF Core seems to sort your changed entities based on their Keys internally for batch operations and you would receive an exception if your Key is not comparable!