我应该首先在 EF 代码中映射双向关系的两侧吗?

cre*_*mor 5 .net c# entity-framework ef-code-first entity-framework-6

假设我有以下实体类:

public class Customer {
  public int Id { get; set; }
  public virtual ICollection<Order> Orders { get; set; }
}

public class Order {
  public int Id { get; set; }
  public virtual Customer Customer { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这些应该如何在 Entity Framework 6 流畅的代码优先映射中映射?我想明确映射,而不是依赖自动映射约定。

选项1

只需映射两个类的本地属性即可。这就是我在 Fluent NHibernate 中的做法。

public class CustomerMap : EntityTypeConfiguration<Customer> {
  public CustomerMap() {
    HasMany(x => x.Orders);
  }
}

public class OrderMap : EntityTypeConfiguration<Order> {
  public OrderMap() {
    HasRequired(x => x.Customer);
  }
}
Run Code Online (Sandbox Code Playgroud)

选项2

在两个类中映射关系的双方。

public class CustomerMap : EntityTypeConfiguration<Customer> {
  public CustomerMap() {
    HasMany(x => x.Orders).WithRequired(x => x.Customer);
  }
}

public class OrderMap : EntityTypeConfiguration<Order> {
  public OrderMap() {
    HasRequired(x => x.Customer).WithMany(x => x.Orders);
  }
}
Run Code Online (Sandbox Code Playgroud)

选项3

映射关系的两侧,但仅在其中一个类中。该代码与选项 2 类似,只是两个构造函数之一为空。


这些选项之间有什么区别吗?如果是,还请解释为什么我应该或不应该使用特定选项。

Ger*_*old 2

我会选择选项 3

在选项 1 中,您可能会忘记映射关联的反向端。在这个简单的示例中,很明显 和Order.CustomerCustomer.Orders同一关联的两端。当事情变得更加复杂时,这一点并不总是显而易见的。而且,它是冗余代码。

在选项 2 中,您可能会遇到冲突的映射。例如当你有...

HasOptional(x => x.Customer).WithMany(x => x.Orders);
Run Code Online (Sandbox Code Playgroud)

...在 中OrderMap,您将收到一个运行时异常,告诉您两个映射不匹配。再说一遍,这是多余的代码。

所以选项 3 是干燥且安全的。唯一的问题是在哪里配置映射有点随意。我倾向于坚持在父母的映射中映射孩子。

还有一条评论。您可能想CustomerId在 中添加一个原始属性Order。映射看起来像:

public class CustomerMap : EntityTypeConfiguration<Customer>
{
    public CustomerMap()
    {
        HasMany(x => x.Orders).WithRequired(x => x.Customer)
                              .HasForeignKey(o => o.CustomerId);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以完全控制关联的两端以及要使用的外键名称。除此之外,与独立关联(没有原始外键属性)相比,这些外键关联还有一些优点。例如,无需从数据库获取父对象即可建立关联的能力。您只需设置一个 Id 值即可。