如何使用 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());
}
}
使用的包
- EntityFramework6.2.0
- MySql.Data 6.10.7
- MySql.Data.实体 6.10.7
不幸的是,目前在 EF 6.x
中是不可能的,您必须处理常规基元。虽然在 EF core 2.1
中可以使用 Value Conversions.
作为经典 .Net Framework
的替代方案,您可以尝试 NHibernate
,因为它允许将值对象作为标识。 NHibernate
从Domain-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; }
}
在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());
}
}
使用的包
- EntityFramework6.2.0
- MySql.Data 6.10.7
- MySql.Data.实体 6.10.7
不幸的是,目前在 EF 6.x
中是不可能的,您必须处理常规基元。虽然在 EF core 2.1
中可以使用 Value Conversions.
作为经典 .Net Framework
的替代方案,您可以尝试 NHibernate
,因为它允许将值对象作为标识。 NHibernate
从Domain-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; }
}