I've trying to create a new foreign key in entity framework core 6 but I am getting the following error?
The types of the properties specified for the foreign key {'RoleId' : RoleId} on entity type 'SomeEntity' do not match the types of the properties in the principal key {'Id' : Guid} on entity type 'DbsRole'. Provide properties that use the same types in the same order.
How can I fix this via Fluent API without adding navigation properties to my entities as I am following DDD principles (bounded contexts etc)?
I thought the conversion handler would be sufficient but obviously not.
RoleId.cs
public record RoleId(Guid Value);
SomeEntity.cs
public class SomeEntity : Entity<Guid>, IAggregateRoot
{
public Guid Id {get; private set;} = null!;
public string Name { get; private set; } = null!;
public RoleId RoleId { get; private set; } = null!;
}
MyContext.cs
public partial class MyContext : IdentityDbContext<MyUser, MyRole, Guid>
{
public virtual DbSet<SomeEntity> SomeEntity { get; set; } = default!;
//... snip...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
_ = modelBuilder.Ignore<RoleId>();
_ = modelBuilder.Entity<SomeEntity>(entity =>
{
_ = entity.HasKey(e => e.Id);
_ = entity.Property(e => e.Name)
.IsRequired();
_ = entity.HasIndex(e => e.Name);
_ = entity.Property(e => e.RoleId)
.IsRequired()
.HasConversion(x => x.Value, x => new RoleId(x));
_ = entity.HasOne<MyRole>()
.WithMany()
.IsRequired()
.HasForeignKey(p => p.RoleId);
});
}
}
MyUser.cs
public class MyUser : IdentityUser<Guid>
{
//... snip...
}
MyRole.cs
public class MyRole : IdentityRole<Guid>
{
// ...snip...
}
Regards
Kyle
CodePudding user response:
How can I fix this via Fluent API without adding navigation properties to my entities as I am following DDD principles (bounded contexts etc)?
You can't (at least currently - up to EF Core 6.0 inclusive). Navigation properties have nothing to do with the problem, which is the type of the PK and FK properties. The error message is quite clear of what is expected
Provide properties that use the same types...
You may consider it EF Core limitation/shortcoming, but it is what it is, and you must follow EF Core data model rules if you want to use it for persisting your domain model.
Which in general means you shouldn't be using the domain model as data model directly. Bounded contexts, value objects, encapsulation - these are not natural for data models. With small exceptions, EF Core context represents a database, DbSet
is a table, entity is a record in that table, and navigation properties are relationships. So the best would be if you create separate models and map between the two where needed. Yes, it requires additional efforts, but that's the only way you can follow the differences between the two models requirements.
But back on the concrete issue. EF Core requires both properties to have one and the same type. This means you either have to use Guid
type for SomeEntity.RoleId
, or use RoleId
type for MyRole.Id
. However the second is not possible with identity model, since both user, role and related things are constrained to have one and the same type of key (the last generic type argument, in your case Guid
). So I'm afraid that if you want to use the domain model as data model directly, the only option currently in this particular case is to make SomeEntity.RoleId
type Guid
.