I have many to many relations in my model:
Tag.cs
public class Tag
{
// more properites ...
// user relations with forgin key
public User CreatedBy { get; set; }
public Guid CreatedById { get; set; }
// has many posts
public ICollection<Post> Posts { get; set; }
}
Here is Tag Canfiguration:
HasRequired(o => o.CreatedBy)
.WithMany(user => user.Tags)
.HasForeignKey(tag => tag.CreatedById)
.WillCascadeOnDelete(false);
Post.cs
public class Post
{
public ICollocation<Tag> Tag { get; set; }
}
And Configuration:
HasMany(post => post.Tags)
.WithMany(tag => tag.Posts)
.MapToStoredProcedures();
Here is insert operation code that I insert Post with Multiple tags:
public async Task InsertAsync(CreatePost postDto)
{
using (var transaction = _uow.Database.BeginTransaction())
{
// map dto class to Post
var post = _mapper.Map<Post>(postDto);
// here split tag names in dto
var postTgs = postDto.TagNames.Split(',');
// i get tags that contains postTags names
var tags = await _tags.AsNoTracking().Where(x => postTgs.Contains(x.Name)).ToListAsync().ConfigureAwait(false);
_posts.Add(post);
await _uow.SaveAllChangesAsync().ConfigureAwait(false);
// get added post for add tags
var newPost = await _posts.Include(o => o.Tags).SingleAsync(x => x.Id == post.Id).ConfigureAwait(false);
foreach (var tag in tags)
{
// here add tags
newPost.Tags.Add(new Tag(){Name = tag.Name,CreatedById = tag.CreatedById});
}
await _uow.SaveAllChangesAsync().ConfigureAwait(false);
transaction.Commit();
}
}
Problem is insert post tags that it insert Multiple tag in database. this opration add new tag in Tag table but i want add exist tags to PostTags that Ef Generated it Automaticaly.
I for solving this problem see other documents and questions but don't get the result.I think that I must create PostTags in my model for solving this.
Note: Tag has a foreign key with user.
why this operation insert new tag?
Because you are adding Tag
instances created with new Tag { ... }
. Since they are not attached to the DbContext
, EF assumes they are new records (not just new links to the existing records).
how can I solve this?
Make sure the Tag
instances are properly attached to the DbContext
with state indicating an existing record.
It's not quite clear from your code, but if _posts
and _tags
are DbSet
s from the same DbContext
used by the _uow
, all you need is to remove AsNoTracking
when getting the tags that contains postTags names, thus enabling correct tracking them as existing, and then simply assign that list as post tags before adding the post to the context, thus telling EF to add links:
var post.Tags = await _tags.Where(x => postTgs.Contains(x.Name)).ToListAsync().ConfigureAwait(false);
_posts.Add(post);
await _uow.SaveAllChangesAsync().ConfigureAwait(false);
transaction.Commit();
Note that transaction is redundant in this case because SaveChanges
already does that for you.