代码优先:独立协会与外国关键协会?

Dan*_*zzi 100 entity-framework poco

每次我开始研究一个新项目时,我都会和自己进行一场心理辩论,而我正在设计我的POCO.我看过很多教程/代码示例似乎都支持外键关联:

外键关联

public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; } // <-- Customer ID
    ...
}
Run Code Online (Sandbox Code Playgroud)

独立协会相反:

独立协会

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}
Run Code Online (Sandbox Code Playgroud)

我以前使用过NHibernate,并且使用了独立的关联,它们不仅感觉更多OO,而且(延迟加载)的优势在于可以让我访问整个Customer对象,而不仅仅是ID.例如,这允许我检索Order实例,然后Order.Customer.FirstName无需显式地进行连接,这非常方便.

所以回顾一下,我的问题是:

  1. 使用独立关联有任何明显的缺点吗?和...
  2. 如果没有,那么使用外键关联的原因是什么?

Lad*_*nka 106

如果您想充分利用ORM,您肯定会使用实体参考:

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}
Run Code Online (Sandbox Code Playgroud)

一旦从具有FK的数据库生成实体模型,它将始终生成实体引用.如果您不想使用它们,则必须手动修改EDMX文件并添加表示FK的属性.至少在实体框架v1中就是这种情况,其中只允许独立关联.

实体框架v4提供了一种称为外键关联的新型关联.独立和外键关联之间最明显的区别在于Order类:

public class Order
{
    public int ID { get; set; }
    public int CustomerId { get; set; }  // <-- Customer ID
    public Customer Customer { get; set; } // <-- Customer object
    ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,您同时拥有FK属性和实体引用.两种类型的关联之间存在更多差异:

独立协会

  • 它表示为单独的对象ObjectStateManager.它有自己的EntityState!
  • 建立关联时,您始终需要来自关联两端的权限
  • 此关联以与实体相同的方式映射.

外键关联

  • 它没有表示为单独的对象ObjectStateManager.因此,您必须遵守一些特殊规则.
  • 建立关联时,您不需要关联的两端.拥有子实体和父实体的PK就足够了,但PK值必须是唯一的.因此,在使用外键关联时,还必须为关系中使用的新生成实体分配临时唯一ID.
  • 此关联未映射,而是定义参照约束.

如果要使用外键关联,则必须在实体数据模型向导中勾选模型中的包含外键列.

编辑:

我发现这两种类型的关联之间的区别并不是很清楚,所以我写了一篇简短的文章,其中包含更多细节以及我对此的看法.


Set*_*son 33

使用两者.并使您的实体引用虚拟以允许延迟加载.像这样:

public class Order
{
  public int ID { get; set; }
  public int CustomerID { get; set; }
  public virtual Customer Customer { get; set; } // <-- Customer object
  ...
}
Run Code Online (Sandbox Code Playgroud)

这节省了不必要的数据库查找,允许延迟加载,并允许您在知道自己想要的内容时轻松查看/设置ID.请注意,两者都不会以任何方式更改表结构.

  • 同意.正如拉迪斯拉夫所说,这就是我最终要做的事情.它真的给你两全其美; 当你需要它的所有属性时的整个对象,以及当你只需要PK并且不关心其余的时它的ID. (5认同)

Yul*_*dra 8

独立关联不能很好地与AddOrUpdate通常在Seed方法中使用的关联.当引用是现有项时,将重新插入.

// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);
Run Code Online (Sandbox Code Playgroud)

结果是现有客户将被重新插入并且新的(重新插入的)客户将与新订单相关联.


除非我们使用外键关联并分配id.

 // Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);
Run Code Online (Sandbox Code Playgroud)

我们有预期的行为,现有客户将与新订单相关联.

  • 这是一个很好的发现。但是,将客户附加到订单的解决方法(我认为是正确的方法)是从 db 上下文加载它,如下所示:`var order = new Order { Id = 1, Customer = db.Customers.Find(1) };` 或者您可以使用 Select 方法从数据库上下文加载客户。这与独立协会合作。 (2认同)