今天在博问中看到一个关于 EF Core 的提问 ef core 2.0 多对多查询的问题 ,由于还没使用过 EF Core 的多对多映射,于是参考 EF Core 帮助文档 快速写了个 .net core 控制台程序(基于 EF Core In-Memory Database)实验了一下。
实体类的定义:
1)Post
1 2 3 4 5 6 7 8 public class Post { public int PostId { get ; set ; } public string Title { get ; set ; } public string Content { get ; set ; } public List<PostTag> PostTags { get ; set ; } }
2)Tag
1 2 3 4 5 6 7 public class Tag { public int TagId { get ; set ; } public string TagName { get ; set ; } public List<PostTag> PostTags { get ; set ; } }
3)PostTag
1 2 3 4 5 6 7 8 public class PostTag { public int PostId { get ; set ; } public Post Post { get ; set ; } public int TagId { get ; set ; } public Tag Tag { get ; set ; } }
DbContext 的定义与映射配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class MyDbContext : DbContext { public DbSet <Post > Posts { get ; set ; } public DbSet <Tag > Tags { get ; set ; } public MyDbContext (DbContextOptions<MyDbContext> options ) : base (options ) { } protected override void OnModelCreating (ModelBuilder modelBuilder ) { modelBuilder.Entity<PostTag>() .HasKey(t => new { t.PostId, t.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); } }
控制台程序 Main 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Program { static async Task Main (string [] args ) { IServiceCollection services = new ServiceCollection(); services.AddDbContext<MyDbContext>(options => { options.UseInMemoryDatabase("blog_sample" ); }); IServiceProvider sp = services.BuildServiceProvider(); var writeDbContext = sp.GetService<MyDbContext>(); var tag = new Tag { TagName = "efcore" }; var post = new Post { Title = "test title" , Content = "test body" }; var postTag = new PostTag { Tag = tag, Post = post }; writeDbContext.Add(postTag); writeDbContext.SaveChanges(); var readDbContext = sp.GetService<MyDbContext>(); var queryPost = await readDbContext.Posts .Include(p => p.PostTags) .ThenInclude(pt => pt.Tag) .FirstOrDefaultAsync(); Console.WriteLine(queryPost.PostTags[0 ].Tag.TagName); } }
查询时需要使用 ThenInclude ,但这里使用 ThenInclude 时 VS2017 的智能感知有个bug ,pt.Tag 感知不出来,详见 Include->ThenInclude for a collection 。
如果使用 SQL Server ,会生成下面的 SQL 语句:
1 2 3 SELECT TOP(1 ) [p].[PostId], [p].[Content], [p].[Title]FROM [Posts] AS [p]ORDER BY [p].[PostId]
1 2 3 4 5 6 7 8 9 SELECT [p.PostTags].[PostId], [p.PostTags].[TagId], [p.Tag].[TagId], [p.Tag].[TagName]FROM [PostTag] AS [p.PostTags]INNER JOIN [Tags] AS [p.Tag] ON [p.PostTags].[TagId] = [p.Tag].[TagId]INNER JOIN ( SELECT TOP(1 ) [p0].[PostId] FROM [Posts] AS [p0] ORDER BY [p0].[PostId] ) AS [t] ON [p.PostTags].[PostId] = [t].[PostId] ORDER BY [t].[PostId]