如何通过fluent在EF Core中正确实现非原始FK

How to implement non-primitive FK correctly in EF Core via fluent

我试图在 entity framework 核心 6 中创建一个新的外键,但出现以下错误?

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.

如何通过 Fluent API 解决此问题,而不向我的实体添加导航属性,因为我遵循 DDD 原则(限界上下文等)?

我认为转换处理程序就足够了,但显然不够。

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...
}

此致

凯尔

How can I fix this via Fluent API without adding navigation properties to my entities as I am following DDD principles (bounded contexts etc)?

你不能(至少目前 - 包括 EF Core 6.0)。导航属性与问题无关,是PK和FK属性的type。错误消息非常清楚预期的内容

Provide properties that use the same types...

你可能认为它是 EF Core limitation/shortcoming,但它就是它,如果你想将它用于坚持你的领域模型。

这通常意味着您不应直接将域模型用作数据模型。限界上下文、值对象、封装——这些对于数据模型来说并不自然。除了少数例外,EF Core 上下文表示数据库,DbSet 是 table,实体是 table 中的记录,导航属性是关系。所以最好的办法是创建单独的模型并在需要的地方在两者之间进行映射。是的,它需要额外的努力,但这是您可以了解两种模型要求之间差异的唯一方法。

但回到具体问题。 EF Core 要求这两个属性具有相同的类型。这意味着您必须为 SomeEntity.RoleId 使用 Guid 类型,或者为 MyRole.Id 使用 RoleId 类型。但是,第二个对于身份模型是不可能的,因为用户、角色和相关事物都被限制为具有一个相同类型的键(最后一个泛型类型参数,在您的情况下 Guid)。所以恐怕如果你想直接使用域模型作为数据模型,目前在这种特殊情况下唯一的选择是使 SomeEntity.RoleId 类型 Guid.