如何使用 fluent api 在 EF6 中映射值对象标识?

How to map a value object identity in EF6 using fluent api?

在DDD中,将一个实体的标识做成一个值对象是一种常见的设计。

示例:

public class FooId : ValueObject  
{  
    public int Id { get; private set; }
}  

public class Foo
{  
    public FooId FooId { get; private set; }
}  

在 EF6 中,我可以使用以下代码映射此类类型:

modelBuilder.ComplexType<SomeType>()
    .Property(x => x.SomeProperty)
    ...

(参见 3 Reasons to Model Identity as A Value Object, IDDD

Edit: IDDD in .Net

但是当我尝试映射 Foo 和 FooId 时,在迁移过程中出现以下错误

The properties expression 'x => x.FooId.Id' is not valid. The expression should represent a property: C#: 't => t.MyProperty' VB.Net: 'Function(t) t.MyProperty'. When specifying multiple properties use an anonymous type: C#: 't => new { t.MyProperty1, t.MyProperty2 }' VB.Net: 'Function(t) New With { t.MyProperty1, t.MyProperty2 }'.

我的配置:

public class FooConfiguration : EntityTypeConfiguration<Foo>
{  
    public FooConfiguration()
    {
        HasKey(x => x.FooId.Id);
    }
}  

public class FooContext : EntityTypeConfiguration<Foo>
{  
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.ComplexType<FooId>();
        modelBuilder.Configurations.Add(new FooConfiguration());
    }
}  

使用的包

不幸的是,目前在 EF 6.x 中是不可能的,您必须处理常规基元。虽然在 EF core 2.1 中可以使用 Value Conversions.

作为经典 .Net Framework 的替代方案,您可以尝试 NHibernate,因为它允许将值对象作为标识。 NHibernateDomain-Driven Design的角度看还是比EF强。

EF 自动识别复杂类型(值对象),您不需要添加任何流畅的 api 映射。

我给你的例子来自 this course, by Julie Lerman

Address 是一个值对象:

public class Address 
{
    public string Street { get; private set; }
    public string City { get; private set; }
    public string StateProvince { get; private set; }
    public string PostalCode { get; private set; }
}

SalesOrder 是我们的实体,它使用 Address 复杂类型。

public class SalesOrder
{
    public int SalesOrderId { get; private set; }
    public DateTime OrderDate { get; private set; }
    public DateTime? DueDate { get; private set; }
    public string PurchaseOrderNumber { get; private set; }
    public string Comment { get; private set; }
    public Address ShippingAddress { get; private set; }
}

现在,如果您首先使用 EF 代码构建您的数据库 tables,这就是您将获得的(迁移代码):

CreateTable("SalesOrder", c => new
{
    SalesOrderId = c.Int(nullable: false),
    OrderDate = c.DateTime(nullable: false),
    DueDate = c.DateTime(),
    PurchaseOrderNumber = c.String(),
    Comment = c.String(),
    ShippingAddress_Street = c.String(),
    ShippingAddress_City = c.String(),
    ShippingAddress_StateProvince = c.String(),
    ShippingAddress_PostalCode = c.String(),
})
.PrimaryKey(t => t.SalesOrderId);

请注意,EF 直接将所有地址字段添加到 table。

您不需要任何额外的流畅 api 映射来让 entity framework 将 Address 字段添加到 table,以上是默认行为。

这是 DbContext 的样子:

public class OrderContext: DbContext
{
    public OrderContext() : base("connectionStringName") { }
    DbSet<SalesOrder> Orders { get; set; }
}