【问题标题】:Many-to-many mapping table多对多映射表
【发布时间】:2012-07-08 03:03:21
【问题描述】:

从我在网上和编程实体框架 CodeFirst 书中看到的示例中,当您在两个类上都有一个集合时,EF 将创建一个映射表,例如 MembersRecipes,并且每个类的主键将链接到该表.

但是,当我执行以下操作时,我会在 Recipes 表中获得一个名为 Member_Id 的新字段,并在 Members 表中获得一个 Recipe_Id

这只会创建两个一对多关系,而不是多对多关系,因此我可以将成员 3 链接到食谱 (4,5,6) 并将食谱 4 链接到成员 (1,2,3 ) 等。

有没有办法创建这个映射表?如果是这样,您如何将其命名为其他名称,例如“食谱”?

谢谢

    public abstract class Entity {
        [Required]
        public int Id { get; set; }
    }   

    public class Member : Entity {
        [Required]
        public string Name { get; set; }

        public virtual IList<Recipe> Recipes { get; set; }
    }

    public class Recipe : Entity {  
        [Required]
        public string Name { get; set; }

        [ForeignKey("Author")]
        public int AuthorId { get; set; }
        public virtual Member Author { get; set; }

            ....

        public virtual IList<Member> Members { get; set; }
    }

更新: 下面是我尝试过的另一种方法,它不使用 Fluent API 并用所有者标志替换 Recipe 上的 AuthorIdAuthor,我还将下面的示例从 Cookbooks 重命名为 MembersRecipes,这也解决了我的问题,类似于答案,但如上所述有进一步的含义。

public class MembersRecipes {

    [Key, Column(Order = 0)]
    [ForeignKey("Recipe")]
    public int RecipeId { get; set; }
    public virtual Recipe Recipe { get; set; }

    [Key, Column(Order = 1)]
    [ForeignKey("Member")]
    public int MemberId { get; set; }
    public virtual Member Member { get; set; }

    public bool Owner { get; set; }
}

RecipeMember 类中,我将集合更改为

public virtual IList<MembersRecipes> MembersRecipes { get; set; }

【问题讨论】:

  • 关于您的更新,在实体框架的说法中,多对多方法称为 带有有效负载的多对多映射 我不知道他们为什么提出一个非常花哨的术语(有效载荷);或者只是我,我的母语不是英语 :-) 我通常将有效载荷这个词与计算机病毒相关联。在 EF 中,有效负载并不是什么险恶的东西,您可以通过使您的表成为有效负载就绪的实体(例如,通过添加额外的 ID 作为主键,因此您需要将现有的多对多复合 pk 转换为独特的复合列)从一开始就
  • 在您的情况下,您没有添加额外的 ID,而是维护了复合主键。表上的 Owner 标志是有效载荷
  • @MichaelBuen 有效载荷是指映射表(关系),您可以在其中放置额外数据(例如关系的创建日期)。如果您应该将 EF 多对多与隐藏表一起使用,则无法将有效负载添加到关系中
  • 对我来说,当我遇到这个问题时,这是因为我的导航属性之一是List,另一个是IEnumerable。我将它们都更改为列表,然后Add-Migration 开始生成 XR 表,而不仅仅是 FK 属性。

标签: c# entity-framework ef-code-first many-to-many


【解决方案1】:

在您的 DbContext OnModelCreating 上执行此操作:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{    
    modelBuilder.Entity<Recipe>()
        .HasMany(x => x.Members)
        .WithMany(x => x.Recipes)
    .Map(x =>
    {
        x.ToTable("Cookbooks"); // third table is named Cookbooks
        x.MapLeftKey("RecipeId");
        x.MapRightKey("MemberId");
    });
}

你也可以反过来做,都是一样的,只是硬币的另一面:

modelBuilder.Entity<Member>()
    .HasMany(x => x.Recipes)
    .WithMany(x => x.Members)
.Map(x =>
{
  x.ToTable("Cookbooks"); // third table is named Cookbooks
  x.MapLeftKey("MemberId");
  x.MapRightKey("RecipeId");
});

更多示例:

http://www.ienablemuch.com/2011/07/using-checkbox-list-on-aspnet-mvc-with_16.html

http://www.ienablemuch.com/2011/07/nhibernate-equivalent-of-entity.html


更新

为了防止对您的作者属性的循环引用,除上述之外,您需要添加以下内容:

modelBuilder.Entity<Recipe>()
    .HasRequired(x => x.Author)
    .WithMany()
    .WillCascadeOnDelete(false);

创意来源:EF Code First with many to many self referencing relationship

核心是,你需要通知 EF Author 属性(它是一个 Member 实例)没有 Recipe 集合(用WithMany() 表示);这样,可以在 Author 属性上停止循环引用。

这些是从上面的 Code First 映射中创建的表:

CREATE TABLE Members(
    Id int IDENTITY(1,1) NOT NULL primary key,
    Name nvarchar(128) NOT NULL
);


CREATE TABLE Recipes(
    Id int IDENTITY(1,1) NOT NULL primary key,
    Name nvarchar(128) NOT NULL,
    AuthorId int NOT NULL references Members(Id)
);


CREATE TABLE Cookbooks(
    RecipeId int NOT NULL,
    MemberId int NOT NULL,
    constraint pk_Cookbooks primary key(RecipeId,MemberId)
);

【讨论】:

  • 感谢您的快速回复,看起来不错,我只是遇到了 1 个问题。我收到此错误:“引用关系将导致不允许的循环引用。[约束名称 = FK_Cookbooks_Members_MemberId]”我假设它与我在食谱实体上的 AuthorId 相关,但我不确定。
  • 谢谢,太好了,我找到了类似的帖子,但没有掌握在没有 lambda 表达式的情况下使用 WithMany() 来配置所需关系的想法:在关系的另一端没有导航属性的许多.当我将其视为将同一作者链接到多个食谱时,这更有意义。谢谢!希望我能再次 + 1。
  • 这也让我觉得我应该稍微重组一些东西,并在“Cookbooks”关系映射表中使用可选的 Owner 标志并取消 Author 属性,但我不确定你是否可以添加属性到 Map() 函数的乘积。
  • 你的多对多表食谱将不再是无负载的,你需要不同的映射。有关确定是否需要多对多关系有效负载的指南,您可以从这个答案开始:stackoverflow.com/questions/3168016/…
  • 感谢该问题的链接,我仍然不完全确定这意味着什么,但查看最佳实践说明,我认为应该使用额外的 ID 字段,因为Recipe & Member 将以不同的方式引用多对多。我还没有完全尝试上面的更新,我注意到的一件事是我需要一种方法来确保每个食谱在 MembersRecipes 表中至少有一个强制所有者标志。我想我可能会坚持我现在所拥有的,即使 Author 属性感觉多余。
猜你喜欢
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-29
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多