当我有这样的模特...

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.OrderIdOrder - 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语句以插入OrderOrderItem。对于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 CustomerIdOrderId@0=5@1=1)。

但是,如果我通过向Customer添加导航属性来向模型的Order实体添加另一个关系...

public Customer Customer { get; set; }


...具有这样的Customer类...

public class Customer
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CustomerId { get; set; }
}


...并调用与上面相同的代码(假设数据库中存在Customer = CustomerId5),我得到以下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


几乎相同,但是在这种情况下CustomerId0@0=0),这会导致违反Order - OrderItem关系的外键约束。如果存在带有Customer = CustomerId0,并且该客户具有带有Order = OrderId1,则不会发生异常,并且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/

10-10 10:41