【问题标题】:Accessing the properties of a many-to-many join entity's navigation properties访问多对多连接实体的导航属性的属性
【发布时间】:2019-07-15 08:13:33
【问题描述】:

PostTag 之间存在多对多关系,由连接实体 PostTag 表示。我目前能够在Post 类的Details 视图中访问PostTag 表;例如,我可以查看特定的Post 并显示关联的PostTags。但是,我只能显示PostTag 属性PostIdTagId,而我想通过PostTag 实体显示与Tag 类相关的属性。

severalposts在线详细说明了显示多对多关系的方法,但它们似乎都与我采用的方法大不相同,因此似乎不容易转化为我的项目.

模型

public class Post
    {
        public int Id { get; set; } // primary key
        public string Title { get; set; }
        public string Description { get; set; }
        public DateTime PublicationDate { get; set; }

        public ICollection<PostTag> PostTags { get; } = new List<PostTag>();
    }

public class Tag
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }

        public ICollection<PostTag> PostTags { get; } = new List<PostTag>();
    }

public class PostTag
    {
        public int PostId { get; set; }
        public Post post { get; set; }

        public int TagId { get; set; }
        public Tag tag { get; set; }
    }

PostsController 的相关部分

public class PostsController : Controller
    {
        private readonly Website.Data.ApplicationDbContext _context;

        public PostsController(Website.Data.ApplicationDbContext context)
        {
            _context = context;
        }
        // GET: Post/Details/5
        public async Task<IActionResult> Details([Bind(Prefix = "Id")]int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var post = await _context.Post
                .Include(p => p.Author)
                .Include(p => p.PostTags)
                .FirstOrDefaultAsync(m => m.Id == id);
            if (post == null)
            {
                return NotFound();
            }

           return View(post);
        }
    }

数据库上下文

public class ApplicationDbContext : IdentityDbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
        public DbSet<Author> Author { get; set; }
        public DbSet<Post> Post { get; set; }
        public DbSet<Tag> Tag { get; set; }
        public DbSet<PostTag> PostTag { get; set; }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            builder.Entity<PostTag>()
                .HasKey(t => new { t.PostId, t.TagId });
        }
    }

查看

@model Website.Models.Post
@foreach (var postTag in Model.PostTags)
{
<tr>
    <td>
        @Html.DisplayFor(modelItem => postTag)
    </td>
</tr>
}

此视图显示与特定Post 关联的PostTags。例如,在https://localhost:xxxxx/Posts/Details/1,访问PostId == 1,并显示其关联的Tags

PostId
1
TagId
2
PostId
1
TagId
4
PostId
1
TagId
5

我似乎无法访问Tag.Title;例如,@Html.DisplayFor(modelItem =&gt; postTag.tag.Title) 不显示任何视图。我想要的输出是,假设FictionNonfictionClassicTag 行的Id 值等于245

Fiction
Nonfiction
Classic

在这里欣赏任何建议。

编辑: 在调试模式下加载详细信息页面时,post 变量包含所有预期的属性,包括PostTagsPostTags 包含预期数量的元素(三个 PostTag 元素,因为此 Post 实例具有三个关联的 Tags)。每个元素包含PostIdTagIdposttag的属性;但是,tagnull。这就是问题所在,因为我正在尝试访问tag.Title。局部变量截图如下:

【问题讨论】:

  • 尝试 .Include(p => PostTags.Tag)。另外请检查您的上下文是否启用了延迟加载。它应该可以工作。
  • 感谢您的评论。在那个Include() 调用中,我似乎无法从PostTags 访问任何其他属性。我不确定延迟加载是什么,将看看那个。我现在将编辑我的帖子以包含我的上下文。
  • @heds1 如果您不熟悉LINQ 语法,请尝试使用LINQ Query 语法。通过这种方式,您可以根据需要定义您的joins。教程可以在这里找到:tutorialsteacher.com/linq/linq-query-syntax
  • @RahulSharma 嗨,感谢您的评论。我的理解是控制器正在使用 LINQ 访问PostTags (var post = await _context.Post.Include(p =&gt; p.PostTags).FirstOrDefaultAsync(m =&gt; m.Id == id);)。我的问题是我不确定如何访问导航属性Tag,以及它的属性Title
  • @heds1 您是否能够在您的Post 模型中获得所需的数据,特别是在您的IColletction PostTags 中。您是否尝试过调试并查看您的查询是否返回了您需要的数据?

标签: c# sql-server asp.net-mvc asp.net-core


【解决方案1】:

您可以使用ThenInclude 方法包含多个级别的相关数据。

var post= await _context.Post
                        .Include(p => p.Author)
                        .Include(p => p.PostTags)
                        .ThenInclude(pt => pt.Tag)
                        .FirstOrDefaultAsync(p => p.Id == id);

多对多 DbContext:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(builder);
    modelBuilder.Entity<PostTag>()
        .HasKey(pt => new { pt.PostId, pt.TagId });

    modelBuilder.Entity<PostTag>()
        .HasOne(pt => pt.Post)
        .WithMany(p => p.PostTags)
        .HasForeignKey(pt => pt.PostId);

    modelBuilder.Entity<PostTag>()
        .HasOne(pt => pt.Tag)
        .WithMany(t => t.PostTags)
        .HasForeignKey(pt => pt.TagId);
}

参考https://docs.microsoft.com/en-us/ef/core/modeling/relationships?view=aspnetcore-2.1#other-relationship-patterns

【讨论】:

  • 太棒了,正确应用 ModelBuilder 是我所缺少的。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多