当我有这样的模特...
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。)
最佳答案
您的模型对我来说看起来很奇怪,我怀疑会引起您的困惑。
根据我所看到的,我猜测您有可以拥有许多订单的客户,每个订单应该只有每种OrderItem类型之一,但是可以有许多OrderItems。一个订单不能属于多个客户。一个OrderItem可以属于多个Order。
如果是这样,那么我认为您需要一个类似的模型;
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)
关于entity-framework - 为什么我必须手动提供外键属性值(在这种情况下)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14553999/