Search code examples
c#asp.net-coreentity-framework-coremany-to-many

Many to many Entity Framework Core how to insert


Based on the tutorial from MS: https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key

This is how we define Post and Tag which have many-many relationship to each other:

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }
    public ICollection<Post> Posts { get; set; }
}

When I run the database-update, it has been able to generate three tables: Post, Tag and PostTag which have the primary key [PostId, TagId]. Overall, the database schema is exactly what I thought.

However, what not mentioned is how to insert a Post with relationship with Tags or vice versa.

db.Posts.Add(new Post { Title="Title1", Content="Content1"});
db.Posts.Add(new Post { Title="Title2", Content="Content2"});
db.Tags.Add(new Tag { TagId="Tag1"});
db.Tags.Add(new Tag { TagId="Tag2"});
db.SaveChanges();

Now the database has 2 records in each table. My question is how can we add a new post that has tag1 and tag2? My code below doesn't work. Can someone point out what was wrong? Or do I need to do the old way by adding a third entity PostTag?

This is my code:

ICollection<Tag> tags = new List<Tag> {db.Tags.FirstOrDefault(i => i.TagId="Tag1"), db.Tags.FirstOrDefault(i => i.TagId="Tag2")};
db.Posts.Add(new Post { Title="Title3", Content="Content3", Tags=tags});

db.SaveChanges();

What I got is the exception saying it cannot insert post3 to the database.

Updated: Thanks for everyone's help. Found out that I made a mistake in my real code. This is my actual code:

vICollection<Tag> tags = new List<Tag> {db.Tags.FirstOrDefault(i => i.TagId="Tag1"), db.Tags.FirstOrDefault(i => i.TagId="Tag2")};
var post3 = new Post { Title="Title3", Content="Content3"};
db.Posts.Add(post3);
post3.Tags = tags; // wrong position, should be called before db.Posts.Add(post3)
db.SaveChanges();

The mistake is post3.Tags = tags; is called after db.Posts.Add(post3);. It should be like this:

vICollection<Tag> tags = new List<Tag> {db.Tags.FirstOrDefault(i => i.TagId="Tag1"), db.Tags.FirstOrDefault(i => i.TagId="Tag2")};
var post3 = new Post { Title="Title3", Content="Content3"};
post3.Tags = tags; // correct position
db.Posts.Add(post3);
db.SaveChanges();

I have also removed PostId from my code.


Solution

  • When you add the Post with specifying the PostId,it will get the following error:

    Cannot insert explicit value for identity column in table 'Posts' when IDENTITY_INSERT is set to OFF.

    Just remove the PostId and the code will work fine:

    ICollection<Tag> tags = new List<Tag> {
               db.Tags.FirstOrDefault(i => i.TagId="Tag1"), 
               db.Tags.FirstOrDefault(i => i.TagId="Tag2")};
    db.Posts.Add(new Post { Title="Title3", Content="Content3", Tags=tags});
    
    db.SaveChanges();