如何定义与 ValueObjects 的嵌套模型关系

How to define nested model relationship with ValueObjects

我有一个 parent child 关系,其中 parent 有一个 ValueObject,我无法确定如何正确定义该关系。

为 Child/Parent 关系添加迁移失败并出现错误...

实体类型'Address'需要定义主键。

以下是当前的代码结构

public class Address
{
        [Required]
        public string BuildingNumber { get; private set; }
        
        // other address properties...
}
public class Parent
{
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; protected set; }

        [Required]
        public Address PrimaryAddress { get; private set; }
}
public class ParentContext : DbContext
{
    public ParentContext(DbContextOptions<ParentContext> options) : 
     base(options)
    {
    }

    public DbSet<Parent> Parents { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Parent>().OwnsOne(p => p.PrimaryAddress);

        // Flatten the ValueObject fields into table
        modelBuilder.Entity<Parent>().OwnsOne(p => p.PrimaryAddress).
            Property(b => b.BuildingNumber).IsRequired().
                HasColumnName("Primary_BuildingName");
     }
}
public class Child
{
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; protected set; }

        [Required]
        public int ParentId { get; private set; }

        [ForeignKey("ParentId")]
        public Parent Parent { get; private set; }
}
public class ChildContext : DbContext
{
    public ChildContext(DbContextOptions<ChildContext> options) : base(options)
    {
    }

    public DbSet<Child> Children { get; set; }
}

使用上面的代码示例,我可以 运行 单独的命令来为 Parent 和 Child 创建迁移,表格看起来是正确的。

add-migration create-parent -c parentcontext

add-migration create-child -c childcontext

添加到实体的关系并添加最终迁移失败。

add-migration add-parent-child-fk -c childcontext

只有当我在不同的上下文中有 Child 和 Parent 时才会出现问题。

我尝试在 parent 和 child 中以不同的方式定义关系以映射地址字段,以便 child 'understands' 映射,但我不能避免我尝试过的任何 EF 错误。

示例项目在这里

https://github.com/cimatt55/ef-parent-valueobject

主要问题是单独的上下文。值对象(拥有的实体类型)只是一个结果 - 如果没有值对象,那么您将遇到其他问题。

您的设计似乎基于错误的假设,即只有实体 类 来自公开的 DbSet。但事实并非如此。还包括导航属性引用的实体,以及它们引用的实体等。

这是合乎逻辑的,因为 EF Core 上下文表示具有表和关系的数据库。 EF Core 需要知道所有相关实体才能正确支持加载相关数据、查询(连接)、级联删除、表、列、主键和外键 property/columns 及其映射等

EF Core 文档的 Including & Excluding Types 部分对此进行了解释:

By convention, types that are exposed in DbSet properties on your context are included in your model. In addition, types that are mentioned in the OnModelCreating method are also included. Finally, any types that are found by recursively exploring the navigation properties of discovered types are also included in the model.

正在为您的 ChildContext 调整他们的示例,发现以下类型:

  • Child 因为它暴露在 DbSet 属性 上下文中
  • Parent 因为它是通过 Child.Parent 导航发现的 属性
  • Address 因为它是通过 Parent.PrimaryAddress 导航发现的 属性

由于 ChildContext 没有 Parent 实体配置,因此 EF 假定与 Parent(和 Address)相关的所有内容都是约定俗成的,因此例外。

简而言之,使用包含相关实体的单独上下文不是一个好主意。解决方案是将所有相关实体放在一个上下文中并进行维护。

看看所使用的术语,您可能已经关注 DDD 和限界上下文,但这些不适合 EF Core(通常在关系数据库)模型中。