简体   繁体   English

实体框架向我的表添加了一个额外的外键

[英]Entity Framework is adding an extra foreign key to my table

I have a very simple data model: a bog standard 1:m relationship. 我有一个非常简单的数据模型:沼泽标准1:m关系。 But I want it slightly denormalised for performance reasons and the EF is not doing what I expect it to do. 但是出于性能原因,我希望它稍微归一化,而EF并没有按照我的预期去做。

I am getting an extra foreign key on a join table when I have a 1:m relationship and also slightly denormalise the data so that my Product table has a reference to a specific order as well as a list of orders. 当我与1:m关系时,我在联接表上得到了一个额外的外键,并且还对该数据进行了一些非规范化处理,因此我的Product表可以引用特定的订单以及订单列表。

Take 2 classes: Customer and Product . 分为2类: CustomerProduct They have am:m relationship, which is to be joined by the Orders class. 它们具有am:m关系,该关系将由Orders类加入。

public class Customer
{
    public int CustomerId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Order> Orders { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Order> Orders { get; set; } 
}

public class Order
{
    public int OrderId { get; set; }
    public virtual Customer Customer { get; set; }
    public virtual Product Product { get; set; }
}

So far so simple. 到目前为止很简单。 Everything is as I expect it to be with the table definitions: 一切都与我期望的表定义一致:

Customers 顾客

CustomerId int
Name nvarchar(MAX)

Products 制品

ProductId int
Name nvarchar(MAX)

Orders 命令

OrderId int
Customer_CustomerId int
Product_ProductId int

Now the issue. 现在的问题。 For reasons I won't go into right now, I want to hold the latest order for a product on the product table itself, rather than have to query and do a WHERE OrderId = MAX(OrderId) on the Orders table. 由于一些原因,我现在不打算讨论,我想在产品表本身上保留某个产品的最新订单,而不是要在Orders表上查询并执行WHERE OrderId = MAX(OrderId)

So I change my model class by adding a single line: 因此,我通过添加一行来更改模型类:

public virtual Order MostRecentOrder { get; set; }

The DB definition for the Product table looks just as I would expect: Product表的数据库定义看起来与我期望的一样:

MostRecentOrder_OrderId int

However, EF has also added a foreign key to the Orders table: 但是,EF Orders表添加了外键:

Product_ProductId1 int

That shouldn't be there. 那不应该在那里。 Only one Order can be the LATEST order, and I have a single instance of the order in my Product class. 只有一个Order可以是最新的Order,而我的Product类中只有一个Order实例。

So I tried doing it a bit more explicitly in the Product class: 因此,我尝试在Product类中更明确地做到这一点:

    public int MostRecentOrderId { get; set; }

    [ForeignKey("MostRecentOrderId")]
    public virtual Order MostRecentOrder { get; set; }

The Product field gets a name change to reflect the explicitly named column in my class, but the Orders table still has that extra foreign key to the Product table. Product字段进行了名称更改,以反映我的班级中显式命名的列,但“ Orders表仍具有该“ Product表的额外外键。

I kept playing and found that I could get rid of the erroneous foreign key on the Orders table by unmapping the Product class: 我一直在玩,发现可以通过取消映射Product类来摆脱Orders表上的错误外键:

    public int? MostRecentOrderId { get; set; }

    [ForeignKey("MostRecentOrderId")]
    [NotMapped]
    public virtual Order MostRecentOrder { get; set; }

I also missed the nullable requirement in my prototype ;) 我也错过了原型中的可为空的要求;)

However, now I cannot make use of pre-loading the data. 但是,现在我无法利用预加载数据。

This code: 这段代码:

ApplicationDbContext db = new ApplicationDbContext();
var products = db.Products.Include("Orders").Include("MostRecentOrder").ToList();

throws this exception: 抛出此异常:

A specified Include path is not valid. 指定的包含路径无效。 The EntityType 'WebApplication1.Models.Product' does not declare a navigation property with the name 'MostRecentOrder'. EntityType'WebApplication1.Models.Product'未声明名称为'MostRecentOrder'的导航属性。

What am I missing here? 我在这里想念什么? I just wish the Product table to have a list of orders, and a reference to one (special) order. 我只希望Product表具有订单列表, 引用一个(特殊)订单。 In traditional client/server dev, I would code this SQL to get the data back: 在传统的客户端/服务器开发人员中,我将对此SQL进行编码以获取数据:

-- to go into the "Product" object
SELECT * 
FROM Products
LEFT JOIN Orders ON Products.MostRecentOrderId = Orders.OrderId;
WHERE ProductId = 4

and

-- to go into the "Product.Orders collection"
SELECT * 
FROM Orders 
WHERE ProductId = 4;

So, after you add the MostRecentOrder navigation property, the Product class would look like this: 因此,在添加MostRecentOrder导航属性之后, Product类将如下所示:

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Order> Orders { get; set; }
    public virtual Order MostRecentOrder { get; set; }
}

What you can do next is use the Fluent API to configure the relationships inside your context class like this: 接下来,您可以使用Fluent API在上下文类中配置关系,如下所示:

public class Context : DbContext
{
    public DbSet<Order> Orders { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Customer> Customers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<Order>()
            .HasRequired(x => x.Product)
            .WithMany(x => x.Orders);

        modelBuilder
            .Entity<Product>()
            .HasOptional(x => x.MostRecentOrder);
    }
}

It seems to me that convention based configuration are not explicit enough to tell EF about your relationships in such case. 在我看来,在这种情况下,基于约定的配置还不够明确,无法告诉EF您的关系。 Fluent API is more explicit. 流利的API更明确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM