codebased
codebased

Reputation: 7073

What is wrong with this many-to-many relationship in EF code-first

I am working on Code First , EF 6.0 and trying to implement Many to Many relationship between Request and Tag tables.

The relationships are set correctly as:

HasMany(b => b.Tags).WithMany().Map(mc => mc.MapLeftKey("RequestID").MapRightKey("TagID").ToTable("requesttags"));

Everything looks alright. However, when it comes to insert tags against Request, I inserting in three ways:

>   if (request.Tags == null)
>             {
>                 entity.Tags = new List<Tag>();
>             }
>              // 1 way get the tag and then insert.
>             var tag = _tagService.Get(1);
               // 2 and 3 way hard code id with the name. 
>             var tags = new List<Tag> {tag, new Tag {Name = ".Net", ID = 2}, new Tag {Name = "C#"}};
> 
>             request.Tags.AddRange(tags);

The insert operation is performed. However, when I see the end result: the first tag has made a reference correctly. However for two tags, even though ID and Names are matching, still it is creating a new record in Tag table and making a reference.

My thought are because the first tag object is get from the database and it is attached. But why do I have to attach?

How can I solve this?

Upvotes: 0

Views: 62

Answers (1)

Yuliam Chandra
Yuliam Chandra

Reputation: 14640

But why do I have to attach?

Because they are disconnected objects and will be treated as new objects. The moment you add the tags into request.Tags, both of them will be marked as Added because EF doesn't know that both of them are existing entities.

You can check the state of each tag by simply loop the Tags.

request.Tags.AddRange(tags);
foreach(var tag in tags)
{
    Console.WriteLine(dbContext.Entry(tag).State);
}

The output should be like:

Unchanged
Added
Added

How can I solve this?

Just Attach it or mark it as Unchanged for the disconnected objects.

dbContext.Entry(tags[1]).State = EntityState.Unchanged;
// equals to dbContext.Set<Tag>().Attach(tags[1]);
dbContext.Entry(tags[2]).State = EntityState.Unchanged;
// equals to dbContext.Set<Tag>().Attach(tags[2]);

And make sure both entities are really existing entities, if not DbUpdateException will be thrown when calling SaveChanges.

Upvotes: 1

Related Questions