ChatGPT解决这个技术问题 Extra ChatGPT

Many-to-many mapping table

From examples that I have seen online and in a Programming Entity Framework CodeFirst book, when you have a collection on both classes EF would create a mapping table such as MembersRecipes and the primary key from each class would link to this table.

However when I do the below, I instead get a new field in the Recipes table called Member_Id and a Recipe_Id in the Members table.

Which only creates two one-to-many relationships, but not a many-to-many so I could have Member 3 linked to Recipes (4,5,6) and Recipe 4 linked to Members (1,2,3) etc.

Is there a way to create this mapping table? and if so how do you name it something else such as "cookbooks" ?

Thanks

    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; }
    }

UPDATE: Below is another approach I have tried which doesn't use the Fluent API and replaces the AuthorId & Author on Recipe with an owner flag, I have also renamed the below example from Cookbooks to MembersRecipes, this also fixes my issue similar to the answer but as mentioned has further implications.

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; }
}

and in Recipe & Member classes I changed the collections to

public virtual IList<MembersRecipes> MembersRecipes { get; set; }
Regarding your update, in Entity Framework's parlance that many-to-many approach is called many-to-many mapping with payload I don't know why they come up with a very fancy term(payload); or it's just me, my native language is not English :-) I usually associate the word payload with computer virus. In EF, payload is not something sinister, you can future-proof your design by making your table a payload-ready entity(e.g. By adding extra ID as primary key, consequently you need to convert your existing many-to-many composite pk to unique composite columns) from the get-go
In your case, you didn't add an extra ID, you maintained the composite primary key. The Owner flag on the table is the payload
@MichaelBuen The payload refers to the mapping table (relationship) where you can put extra data (e.g. creation date of the relationship) in . If you should use EF many-to-many with a hidden table, you cannot add a payload to the relationship
For me when I had this problem, it was because one of my navigation properties was a List and the other was an IEnumerable. I changed them to both be lists and then Add-Migration started generating a XR table instead of just the FK properties.

C
Community

Do this on your 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");
    });
}

You can do it the other way around too, it's the same, just another side of the same coin:

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

Further examples:

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

UPDATE

To prevent cyclical reference on your Author property, aside from above, you need to add this:

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

Idea sourced here: EF Code First with many to many self referencing relationship

The core thing is, you need to inform EF that the Author property(which is a Member instance) has no Recipe collections(denoted by WithMany()); that way, cyclical reference could be stopped on Author property.

These are the created tables from the Code First mappings above:

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

Thanks for the quick reply, looks good I'm just getting 1 problem. I get this error: "The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name = FK_Cookbooks_Members_MemberId ]" I am assuming its related to my AuthorId on the Recipe entity but I'm not sure.
Thanks thats great, I found similar posts but didnt grasp the idea of using WithMany() without the lambda expression to configure the relationship to be required:many without a navigation property on the other side of the relationship. Which makes more sense when I look at it as having the same author linked to multiple recipes. Thanks! wish I could + 1 again.
This also makes me think that I should restructure things slightly and use an optional Owner flag in the "Cookbooks" relationship mapping table and do away with the Author property, but im not sure if you can add properties to a product of the Map() function.
Your many-to-many table Cookbooks will not be payload-free anymore, you shall need different mapping then. For guidelines on determining whether you need a payload on many-to-many relationship or not, you can start from this answer: stackoverflow.com/questions/3168016/…
Thanks for the link to that question, I'm still not entirely sure what that means but looking at the best practice note, the point is made that an extra ID field should be used, I presume because Recipe & Member would reference the many-to-many in a different way. I have not fully tried out my update above yet, one thing I did notice is I would need a way to make sure each Recipe had at least 1 mandatory owner flag in the MembersRecipes table. Thinking I might stick with what I have got for now, even if the Author property feels redundant.

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now