EntityFramework同桌多对多关系

use*_*620 44 c# sql asp.net entity-framework

我有一个名为Products的表,显然包含产品.但是,我需要创建相关产品.所以我所做的就是创建一个名为product_related的联结表,它有两个PK.Products表中的ProductID和Products表中的RelatedID.

我已经使用EF并在其他表上设置了所有内容.我应该如何正确地添加它以便与产品建立关系: product.Products.Add(product object here).当然,这里product代表了我从db中获取的产品对象db.Products.FirstOr....

我该怎么做呢?同桌的多对多?

谢谢.

Sla*_*uma 83

为了使用Database-First方法创建多对多关系,您需要设置遵循某些规则的数据库模式:

  • 创建一个Products以列ProductID为主键的表
  • 创建一个ProductRelations包含列ProductID和列的表,RelatedID并将两列标记为主键(复合键)
  • 不要向ProductRelations表中添加任何其他列.两个键列必须是表中唯一的列,以便EF将此表识别为多对多关系的链接表
  • 在两个表之间创建两个外键关系:
    • 第一个关系将Products表作为primary-key-table,使用ProductIDas主键,将ProductRelationstable作为foreign-key-table,只使用ProductIDas外键
    • 第二个关系也将Products表作为primary-key-table,使用ProductIDas主键,将ProductRelationstable作为foreign-key-table,只使用RelatedIDas外键
  • 为两个关系中的第一个启用级联删除.(你不能两者都做.SQL Server不允许这样做,因为它会导致多个级联删除路径.)

如果从这两个表生成实体数据模型,现在只能获得一个实体,即Product实体(或者Products如果禁用单一化).链接表ProductRelations不会作为实体公开.

Product实体将具有两个导航属性:

public EntityCollection<Product> Products { get { ... } set { ... } }
public EntityCollection<Product> Products1 { get { ... } set { ... } }
Run Code Online (Sandbox Code Playgroud)

这些导航集合是相同多对多关系的两个端点.(如果您有两个不同的表,你希望通过一个多一对多的关系联系起来,说表AB,一个导航集(Bs)将在实体A和其他(As)将是实体B,但因为你的关系是"自我- 引用"两个导航属性都在实体中Product.)

这两个属性的含义是:Products与给定产品相关Products1的产品是指涉及给定产品的产品.例如:如果关系意味着产品需要其他产品作为制造零件,并且您拥有产品"笔记本","处理器","硅芯片",那么"处理器" "硅芯片" 制成( "硅芯片" chips"是产品实体Products集合中的一个元素", "Notebook"使用("Notebook"是产品实体集合中的一个元素).而不是和名称,然后更合适.ProcessorProducts1ProcessorProductsProducts1MadeOfUsedBy

如果您只对关系的一方感兴趣,则可以安全地从生成的模型中删除其中一个集合.只需删除Products1模型设计器表面中的示例.您还可以重命名属性.这种关系仍然是多对多的.

编辑

正如评论中所述,使用Code-First方法的模型和映射将是:

模型:

public class Product
{
    public int ProductID { get; set; }

    public ICollection<Product> RelatedProducts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

制图:

public class MyContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .HasMany(p => RelatedProducts)
            .WithMany()
            .Map(m =>
            {
                m.MapLeftKey("ProductID");
                m.MapRightKey("RelatedID");
                m.ToTable("product_related");
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @drzaus:看我的编辑.我之前实际上已经有了这个答案,但是当我注意到DB-First被问到时,我就删除了它.现在从已删除的答案中抓取代码:) (4认同)
  • Code-First怎么样?如何指定关系(使用Fluent API)? (3认同)
  • 正是我在寻找@Slauma (2认同)
  • 如果你想让延迟加载工作,不要忘记将`RelatedProducts`属性标记为`virtual`,否则你可能会发现它似乎总是空的,除非你在需要时特意包含/加载它们. (2认同)
  • 不应该是: .HasMany(p =&gt; p.RelatedProducts) 吗? (2认同)
  • 嘿。知道为什么我不断收到有关 CollectionNavigationBuilder&lt;Person, Person&gt; 不包含 WithMany() 定义的错误吗?我是否缺少对图书馆之类的参考? (2认同)