当我有这样的模特......
public class Order
{
[Key, Column(Order = 1)]
public int CustomerId { get; set; }
[Key, Column(Order = 2)]
public int OrderId { get; set; }
public ICollection<OrderItem> Items { get; set; }
}
public class OrderItem
{
[Key, Column(Order = 1)]
public int CustomerId { get; set; }
[Key, Column(Order = 2)]
public int OrderId { get; set; }
[Key, Column(Order = 3)]
public int OrderItemId { get; set; }
}
...当我向数据库添加OrderItem.CustomerId
图表时,我不需要手动提供外键值OrderItem.OrderId
和Order - OrderItems
:
var order = new Order
{
CustomerId = 5,
OrderId = 1,
Items = new List<OrderItem>
{
// I don't need to set CustomerId and OrderId here
new OrderItem { OrderItemId = 12 }
}
};
context.Orders.Add(order);
context.SaveChanges();
SaveChanges
将生成SQL语句以插入Order
和OrderItem
。对于OrderItem
,它是:
exec sp_executesql N'insert
[dbo].[OrderItems]([CustomerId], [OrderId], [OrderItemId])
values (@0, @1, @2)
',N'@0 int,@1 int,@2 int',@0=5,@1=1,@2=12
因此,FK CustomerId
和OrderId
已正确设置(@0=5
和@1=1
)。
但是,如果我通过向Customer
添加导航属性,将Order
实体的另一个关系添加到模型中......
public Customer Customer { get; set; }
...像这样的Customer
类......
public class Customer
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CustomerId { get; set; }
}
...并调用与上面相同的代码(假设数据库中存在Customer
CustomerId
= 5
)我得到以下SQL:
exec sp_executesql N'insert
[dbo].[OrderItems]([CustomerId], [OrderId], [OrderItemId])
values (@0, @1, @2)
',N'@0 int,@1 int,@2 int',@0=0,@1=1,@2=12
几乎相同,但在这种情况下CustomerId
为0
(@0=0
)会导致Order - OrderItem
关系违反外键约束。如果存在Customer
CustomerId
= 0
且此客户的Order
OrderId
= 1
,则不会发生任何异常, OrderItem
会被添加到错误的订单中,这可能比例外更糟糕。
可以通过在新CustomerId
中设置OrderItem
(这是FK的一部分)来解决问题:
Items = new List<OrderItem>
{
// I don't need to set OrderId here, BUT CustomerId
new OrderItem { CustomerId = 5, OrderItemId = 12 }
}
或者 - 可以通过将具有Id 5
的客户附加到上下文来修复它(我不知道它为什么会起作用)。
是否有合理的解释为什么我必须手动提供FK(或本例中的部分FK)或这是一个错误?
(我已将EF 5.0与.NET 4.0一起用于此模型。)
答案 0 :(得分:0)
你的模型对我来说很奇怪,我怀疑会引起你的困惑。
基于我所看到的我猜你有客户可以拥有多个订单,每个订单应该只有每种类型的OrderItem,但可以有许多OrderItems。一个订单不能属于多个客户。一个OrderItem可以属于多个订单。
如果这是真的那么我认为你需要一个类似的模型;
public class Customer
{
//Is the key by naming convention or you could use [Key]
public Guid CustomerId { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
//Is the key by naming convention or you could use [Key]
public Guid OrderId { get; set; }
public Guid CustomerId { get; set; } //This doesn't need to be part of the key
public Customer Customer { get; set; }
public ICollection<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
[Key, Column(Order = 0)]
public Guid OrderItemId { get; set; }
[Key, Column(Order=1)]
public Guid OrderId { get; set; }
public ICollection<Order> Orders { get; set; }
}
然后,当您需要查询是否需要了解客户的OrderItems时,您可以使用Include或使用数据投影(例如
)来实现OrderItems.Select(x=>new {
CustomerId = x.Order.Customer.Id,
//this rest of your properties
});
或者如果你想要整个实体
OrderItems.Include(x=>x.Order.Customer)