【问题标题】:How to map a value object identity in EF6 using fluent api?如何使用流利的 api 在 EF6 中映射值对象标识?
【发布时间】: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 ObjectIDDD

编辑: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

【问题讨论】:

    标签: mysql entity-framework-6 domain-driven-design entity-framework-migrations


    【解决方案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 的建议
      猜你喜欢
      • 2013-10-28
      • 2011-06-18
      • 1970-01-01
      • 2012-12-07
      • 2013-10-27
      • 2014-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多