访问多对多连接实体的导航属性

时间:2019-07-15 08:13:33

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

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

网上有several posts详细说明了显示多对多关系的方式,但是它们似乎与我所采用的方法大不相同,因此似乎并不容易可翻译为我的项目。

模型

PostTag

PostsController的相关部分

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; }
    }

Db上下文

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> } 关联的PostTags。例如,在Post,访问带有https://localhost:xxxxx/Posts/Details/1的{​​{1}},并显示其关联的Post

Id == 1

我似乎无法访问Tags;例如,PostId 1 TagId 2 PostId 1 TagId 4 PostId 1 TagId 5 不显示任何视图。我期望的输出是,假设Tag.Title@Html.DisplayFor(modelItem => postTag.tag.Title)Tag的{​​{1}}行的Fiction值等于Nonfiction,{{1} }和Classic

Id

在这里感谢任何建议。

修改: 在调试模式下加载“详细信息”页面后,2变量包含所有期望的属性,包括45包含元素的预期数量(三个Fiction Nonfiction Classic 元素,因为此post实例具有三个关联的PostTags)。每个元素都包含PostTagsPostTagPostTags的属性;但是,PostIdTagId。这是问题,因为我正在尝试访问post。下面的局部变量的屏幕截图:

local variables

1 个答案:

答案 0 :(得分:2)

您可以使用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