如何使用流利的 api 在 EF6 中映射值对象标识?
Posted
技术标签:
【中文标题】如何使用流利的 api 在 EF6 中映射值对象标识?【英文标题】:How to map a value object identity in EF6 using fluent api? 【发布时间】:2019-03-13 21:24:30 【问题描述】:在 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)
编辑:IDDD in .Net
但是当我尝试映射 Foo 和 FooId 时,在迁移过程中出现以下错误
属性表达式“x => x.FooId.Id”无效。该表达式应表示一个属性:C#: 't => t.MyProperty' VB.Net: 'Function(t) t.MyProperty'。指定多个属性时使用匿名类型: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());
使用的包
EntityFramework 6.2.0 mysql.Data 6.10.7 MySql.Data.Entity 6.10.7【问题讨论】:
【参考方案1】:不幸的是,目前在EF 6.x
中是不可能的,您必须处理常规原语。虽然在EF core 2.1
中使用Value Conversions 是可能的。
作为经典.Net Framework
的替代方案,您可以尝试NHibernate
,因为它允许将值对象作为身份。从Domain-Driven Design
的角度来看,NHibernate
看起来仍然比EF
更强大。
【讨论】:
【参考方案2】: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 代码来构建您的数据库表,您将得到以下结果(迁移代码):
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是直接把所有地址字段加到表中的。
您不需要任何额外的流利的api映射来让实体框架将Address
字段添加到表中,以上是默认行为。
DbContext
是这样的:
public class OrderContext: DbContext
public OrderContext() : base("connectionStringName")
DbSet<SalesOrder> Orders get; set;
【讨论】:
感谢您的评论。我的项目中有很多价值对象,是的,我可以用 EF 正确映射它们。我试图实现的唯一一件事是也将值对象用作身份,正如@Albert 所述,EF 目前不支持该身份。我想也许有其他人使用它来工作的解决方法,这就是我在 SO 上发布这个问题的原因。现在我仍在使用原语作为我的身份,因为在我当前的项目中迁移到另一个 ORM 对我来说有点昂贵,也许在我的下一个项目中,我会尝试 Albert 的建议以上是关于如何使用流利的 api 在 EF6 中映射值对象标识?的主要内容,如果未能解决你的问题,请参考以下文章