无法将数据插入到Entity Framework C# .Net7的多对多关系中。

huangapple go评论65阅读模式
英文:

Can't Insert Data Into Many to Many Relationship With Entity Framework C# .Net7

问题

我知道这可能已经被问了数百次,如果不是数千次的话。我已经在这个问题上工作了两天,看了几个答案并尝试了几个示例。我越来越感到困惑。

我有一个论坛应用程序,有一个Forums表和一个Tags表。每个论坛可以有多个标签,每个标签可以分配给多个论坛。标签表中的每个标签都是唯一的。

public class Forum : BaseModel
{        
    public string? Title { get; set; }
    public List<Post> Posts { get; set; } = new List<Post>();
    public ICollection<ForumTag> ForumTags { get; set; } = new List<ForumTag>();
}

public class Tag : BaseModel
{
    public string? Name { get; set; }
    public ICollection<ForumTag> ForumTags { get; set; } = new List<ForumTag>()
}

public class ForumTag
{
    public int ForumId { get; set; }
    public int TagId { get; set; }

    [NotMapped]
    public Forum forum { get; set; } = new();
    [NotMapped]
    public Tag tag { get; set; } = new();
}

modelBuilder.Entity<ForumTag>()
    .HasKey(t => new { t.ForumId, t.TagId });

modelBuilder.Entity<ForumTag>()
    .HasOne(pt => pt.forum)
    .WithMany(p => p.ForumTags)
    .HasForeignKey(pt => pt.ForumId);

modelBuilder.Entity<ForumTag>()
    .HasOne(pt => pt.tag)
    .WithMany(t => t.ForumTags)
    .HasForeignKey(pt => pt.TagId);

CreateMap<Forum, ForumViewModel>();

CreateMap<ForumViewModel, Forum>()
    .ForMember(q => q.CreatedBy, options => options.Ignore());
    //.ForMember(q => q.ForumTags, options => options.Ignore());

CreateMap<Post, PostViewModel>();
CreateMap<PostViewModel, Post>()
    .ForMember(x => x.CreatedBy, options => options.Ignore());

CreateMap<Tag, TagViewModel>();
CreateMap<TagViewModel, Tag>()
    .ForMember(x => x.Id, options => options.Ignore());
    //.ForMember(x => x.ForumTags, options => options.Ignore());

//CreateMap<ForumTagViewModel, ForumTag>()
//    .ForMember(q => q.forum, options => options.Ignore())
//    .ForMember(q => q.tag, options => options.Ignore());


public async Task<ActionResult<ForumViewModel>> PostForum(ForumViewModel forumViewModel)
{
    Forum? forum = null;

    try
    {                
        forum = _mapper.Map<Forum>(forumViewModel);
        _context.Forums.Add(forum);
        await _context.SaveChangesAsync();

        List<ForumTag> tags = new();                

        foreach(TagViewModel tag in forumViewModel.SelecteTags)
        {
            tags.Add(new()
            {
                ForumId = forum.Id,
                TagId = tag.Id
            });
        }
        _context.ForumTags.AddRange(tags);
        _context.SaveChanges();
    }
    catch (Exception ex)
    {

        return Problem($"Unable to post new forum.\n\n{ex}");
    }

    forumViewModel.Id = forum.Id;

    return CreatedAtAction("GetForumViewModel", new { id = forumViewModel.Id }, forumViewModel);
}

所以目前在这个代码段之后:

forum = _mapper.Map<Forum>(forumViewModel);
_context.Forums.Add(forum);
await _context.SaveChangesAsync();

Forums表和Tag表都正确填充,以及Post表。

在此之后:

_context.ForumTags.AddRange(tags);
_context.SaveChanges();

会创建一个新的空forum记录和一个新的空tag记录。ForumTag表具有来自空forum和tag记录的ID。

我需要做的是插入一个新的forum记录,一个新的post记录和ForumTag的ID。我对Post记录没有任何问题。能否有人指点我正确的方向?

英文:

I know this has probably been asked hundreds, if not thousands of times. I have been working on this for 2 days and I have looked at several answers and tried following several examples. I have been getting more and more confused.

I have a forum app with a Forums table and a Tags table. Each forum can have many tags. Each tag can be assigned to many forums. Each tag in the tags table is unique.

public class Forum : BaseModel
{        
public string? Title { get; set; }
public List&lt;Post&gt; Posts { get; set; } = new List&lt;Post&gt;();
public ICollection&lt;ForumTag&gt; ForumTags { get; set; } = new List&lt;ForumTag&gt;();
}
public class Tag : BaseModel
{
public string? Name { get; set; }
public ICollection&lt;ForumTag&gt; ForumTags { get; set; } = new List&lt;ForumTag&gt;()
}
public class ForumTag
{
public int ForumId { get; set; }
public int TagId { get; set; }
[NotMapped]
public Forum forum { get; set; } = new();
[NotMapped]
public Tag tag { get; set; } = new();
}
modelBuilder.Entity&lt;ForumTag&gt;()
.HasKey(t =&gt; new { t.ForumId, t.TagId });
modelBuilder.Entity&lt;ForumTag&gt;()
.HasOne(pt =&gt; pt.forum)
.WithMany(p =&gt; p.ForumTags)
.HasForeignKey(pt =&gt; pt.ForumId);
modelBuilder.Entity&lt;ForumTag&gt;()
.HasOne(pt =&gt; pt.tag)
.WithMany(t =&gt; t.ForumTags)
.HasForeignKey(pt =&gt; pt.TagId);
CreateMap&lt;Forum, ForumViewModel&gt;();
CreateMap&lt;ForumViewModel, Forum&gt;()
.ForMember(q =&gt; q.CreatedBy, options =&gt; options.Ignore());
//.ForMember(q =&gt; q.ForumTags, options =&gt; options.Ignore());
CreateMap&lt;Post, PostViewModel&gt;();
CreateMap&lt;PostViewModel, Post&gt;()
.ForMember(x =&gt; x.CreatedBy, options =&gt; options.Ignore());
CreateMap&lt;Tag, TagViewModel&gt;();
CreateMap&lt;TagViewModel, Tag&gt;()
.ForMember(x =&gt; x.Id, options =&gt; options.Ignore());
//.ForMember(x =&gt; x.ForumTags, options =&gt; options.Ignore());
//CreateMap&lt;ForumTagViewModel, ForumTag&gt;()
//    .ForMember(q =&gt; q.forum, options =&gt; options.Ignore())
//    .ForMember(q =&gt; q.tag, options =&gt; options.Ignore());
public async Task&lt;ActionResult&lt;ForumViewModel&gt;&gt; PostForum(ForumViewModel forumViewModel)
{
Forum? forum = null;
try
{                
forum = _mapper.Map&lt;Forum&gt;(forumViewModel);
_context.Forums.Add(forum);
await _context.SaveChangesAsync();
List&lt;ForumTag&gt; tags = new();                
foreach(TagViewModel tag in forumViewModel.SelecteTags)
{
tags.Add(new()
{
ForumId = forum.Id,
TagId = tag.Id
});
}
_context.ForumTags.AddRange(tags);
_context.SaveChanges();
}
catch (Exception ex)
{
return Problem($&quot;Unable to post new forum.\n\n{ex}&quot;);
}
forumViewModel.Id = forum.Id;
return CreatedAtAction(&quot;GetForumViewModel&quot;, new { id = forumViewModel.Id }, forumViewModel);
}

So currently after

forum = _mapper.Map&lt;Forum&gt;(forumViewModel);
_context.Forums.Add(forum);
await _context.SaveChangesAsync();

The forums table and Tag table are correctly populated, as well as the Post table.

After

 _context.ForumTags.AddRange(tags);
_context.SaveChanges();

A new null forum record is created and a new null tag record is created. The ForumTag table has the id's from the null forum and tag record.

What I need to do is insert a new forum record, a new post record, and the ForumTag Id's. I'm not having any issues with the Post records.

Can someone please point me in the right direction?

答案1

得分: 0

以下是翻译好的部分:

好吧,像往常一样,我在发布帖子后才弄清楚了。我找到了这篇博客[在EF Core 5及以上版本中更新多对多关系][1]

public class Forum : BaseModel
{
    public string? Title { get; set; }
    public List<Post> Posts { get; set; } = new List<Post>();
    public List<Tag>? Tags { get; set; }
}

public class Tag : BaseModel
{
    public string? Name { get; set; }
    public ICollection<Forum> Forums { get; set; }
}

public class ForumTag
{
    public int ForumId { get; set; }
    public int TagId { get; set; }
    public Forum forum { get; private set; }
    public Tag tag { get; private set; }
}

modelBuilder.Entity<Forum>().HasMany(x => x.Tags)
        .WithMany(x => x.Forums)
        .UsingEntity<ForumTag>(
            x => x.HasOne(x => x.tag)
            .WithMany().HasForeignKey(x => x.TagId),
            x => x.HasOne(x => x.forum)
           .WithMany().HasForeignKey(x => x.ForumId));

public async Task<ActionResult<ForumViewModel>> PostForum(ForumViewModel forumViewModel)
{
    Forum? forum = null;

    try
    {
        var viewModelTags = forumViewModel.SelecteTags;

        List<Tag> tags = new List<Tag>();

        foreach (var item in viewModelTags)
        {
            Tag tag = await _context.Tags.FirstOrDefaultAsync(x => x.Name == item.Name);
            tags.Add(tag);
        }

        forum = _mapper.Map<Forum>(forumViewModel);
        forum.Tags = new();
        forum.Tags.AddRange(tags);

        _context.Add(forum);
        _context.SaveChanges();
    }
    catch (Exception ex)
    {

        return Problem($"无法发布新的论坛。\n\n{ex}");
    }

    forumViewModel.Id = forum.Id;

    return CreatedAtAction("GetForumViewModel", new { id = forumViewModel.Id }, forumViewModel);
}

<details>
<summary>英文:</summary>
Well, as happens from time to time, I figured it out after I created a post here. I found this blog [Updating many-to-many relationships in EF Core 5 and above][1]

public class Forum : BaseModel
{
public string? Title { get; set; }
public List<Post> Posts { get; set; } = new List<Post>();
public List<Tag>? Tags { get; set; }
}

public class Tag : BaseModel
{
public string? Name { get; set; }
public ICollection<Forum> Forums { get; set; }
}

public class ForumTag
{
public int ForumId { get; set; }
public int TagId { get; set; }
public Forum forum { get; private set; }
public Tag tag { get; private set; }
}

modelBuilder.Entity<Forum>().HasMany(x => x.Tags)
.WithMany(x => x.Forums)
.UsingEntity<ForumTag>(
x => x.HasOne(x => x.tag)
.WithMany().HasForeignKey(x => x.TagId),
x => x.HasOne(x => x.forum)
.WithMany().HasForeignKey(x => x.ForumId));

public async Task<ActionResult<ForumViewModel>> PostForum(ForumViewModel forumViewModel)
{
Forum? forum = null;

try
{
var viewModelTags = forumViewModel.SelecteTags;
List&lt;Tag&gt; tags = new List&lt;Tag&gt;();
foreach (var item in viewModelTags)
{
Tag tag = await _context.Tags.FirstOrDefaultAsync(x =&gt; x.Name == item.Name);
tags.Add(tag);
}
forum = _mapper.Map&lt;Forum&gt;(forumViewModel);
forum.Tags = new();
forum.Tags.AddRange(tags);
_context.Add(forum);
_context.SaveChanges();
}
catch (Exception ex)
{
return Problem($&quot;Unable to post new forum.\n\n{ex}&quot;);
}
forumViewModel.Id = forum.Id;
return CreatedAtAction(&quot;GetForumViewModel&quot;, new { id = forumViewModel.Id }, forumViewModel);

}


[1]: https://www.thereformedprogrammer.net/updating-many-to-many-relationships-in-ef-core-5-and-above/
</details>

huangapple
  • 本文由 发表于 2023年6月13日 09:19:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定