EntityFramework同一张表多对多关系

Posted

技术标签:

【中文标题】EntityFramework同一张表多对多关系【英文标题】:EntityFramework Same Table Many to Many Relationship 【发布时间】:2012-08-27 14:04:15 【问题描述】:

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

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

我应该如何正确地做到这一点?多对多到同一张表?

谢谢。

【问题讨论】:

如果这将是生产软件,请不要在单个表上使用 M2M,它可以并且确实可以工作,但是维护起来很痛苦,我现在正在工作,但是如果到我回家时你还没有得到答案,我会给你一个合适的解决方案来解决你的问题。 您是问如何使用实体框架添加到product_related表中? @Chazt3n 有什么替代方案? 【参考方案1】:

为了使用数据库优先方法创建多对多关系,您需要设置遵循特定规则的数据库架构:

创建一个Products 表,以ProductID 列作为主键 创建一个ProductRelations 表,其中包含一列ProductID 和一列RelatedID,并将两列都标记为主键(复合键) 不要在ProductRelations 表中添加任何其他列。两个关键列必须是表中唯一的列,才能让 EF 将此表识别为多对多关系的链接表 在两个表之间创建两个外键关系: 第一个关系将Products 表作为主键表,ProductID 作为主键,ProductRelations 表作为外键表,只有ProductID 作为外键 第二个关系也有Products表作为主键表,ProductID作为主键,ProductRelations表作为外键表,只有RelatedID作为外键键 为两个关系中的第一个启用级联删除。 (您不能同时这样做。SQL Server 不允许这样做,因为它会导致多个级联删除路径。)

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

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

public EntityCollection<Product> Products  get  ...  set  ...  
public EntityCollection<Product> Products1  get  ...  set  ...  

这些导航集合是同一个多对多关系的两个端点。 (如果您想通过多对多关系链接两个不同的表,例如表AB,一个导航集合(Bs)将在实体A 中,另一个(@ 987654344@) 将在实体 B 中。但是因为您的关系是“自引用”的,所以两个导航属性都在实体 Product 中。)

这两个属性的含义是:Products是与给定产品相关的产品,Products1是与给定产品相关的产品。例如:如果关系意味着一个产品需要其他产品作为部件来制造,并且您有产品“笔记本电脑”、“处理器”、“硅芯片”,那么“处理器”是制成的“硅芯片”(“硅芯片”是Processor 产品实体的Products 集合中的一个元素)并且“笔记本”使用(“笔记本”是Products1 Processor 产品实体的集合)。代替 ProductsProducts1 名称 MadeOfUsedBy 会更合适。

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

编辑

正如评论中所问的那样,使用代码优先方法的模型和映射将是:

型号:

public class Product

    public int ProductID  get; set; 

    public ICollection<Product> RelatedProducts  get; set; 

映射:

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");
            );
    

【讨论】:

Code-First 怎么样?您如何指定关系(使用 Fluent API)? @drzaus:见我的编辑。我之前实际上有这个答案,但是当我注意到 DB-First 被问到时,我把它删除了。现在从已删除的答案中获取代码:) 正是我要找的@Slauma 如果你想让延迟加载工作,不要忘记将RelatedProducts 属性标记为virtual --- 否则你可能会发现它似乎总是空的,除非你特别包含/加载这些在你需要的时候。 不应该是:.HasMany(p => p.RelatedProducts) 吗?【参考方案2】:

让我们举个例子:

相关

  Related_id      PK
  Related_name
  Date

产品

  Product_id      PK
  Related_id      FK
  Product_Name
  Date

如何在 EF 中表示

相关模型类命名为 RelatedModel

  [Key]
  public int Related_id  get; set; 

  public string Related_name get;set

  public Datetime Dateget;set;

产品模型类命名为 ProductModel

   [Key]
  public int Product_id  get; set; 

  public string Product_name get;set

  public string Related_id get;set

  public Datetime Dateget;set;

  [ForeignKey("Related_id ")]      //We  can also specify here Foreign key
  public virtual RelatedModel Related  get; set;  

这样我们可以在两个表之间建立关系

现在在多对多关系的情况下,我想在这里再举一个例子

假设我有一个模型类Enrollment.cs

public class Enrollment

    public int EnrollmentID  get; set; 
    public int CourseID  get; set; 
    public int StudentID  get; set; 
    public decimal? Grade  get; set; 
    public virtual Course Course  get; set; 
    public virtual Student Student  get; set; 

这里CourseID和StudentId是两个外键

现在我有另一个类Course.cs,我们将在其中创建多对多关系。

public class Course

    public int CourseID  get; set; 
    public string Title  get; set; 
    public int Credits  get; set; 
    public virtual ICollection<Enrollment> Enrollments  get; set; 

希望这会有所帮助!!!

【讨论】:

你的回答离问题真的很远。 1)你的第一个例子是一对多的,2)第二个也是一对多的(尽管你说它是多对多的)。 3)您的关系不在同一张表之间,并且 4)他没有像您的示例那样使用 Code-First。

以上是关于EntityFramework同一张表多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

与同一张表的关系(多对多?) - Laravel

Laravel 定义同一张表的多对多关系

Sequelize 多对多关系同一张表

实体框架代码优先,同一张表上的多对多关系

ON CASCADE DELETE 对同一张表之间的多对多关系

同一张表之间多对多的级联删除