EF多对多关系中如何利用关系表(EF4.1 Many to Many involves junction table details)
请先看dudu的文章http://www.cnblogs.com/dudu/archive/2011/07/09/entity_framework_many_to_many.html
一般的多对多关系数据库表:
Mapping代码:
- modelBuilder.Entity<BlogPost>()
- .HasMany(b => b.Categories)
- .WithMany(c => c.CategoryBlogPosts)
- .Map
- (
- m =>
- {
- m.MapLeftKey("BlogPostID");
- m.MapRightKey("CategoryID");
- m.ToTable("BlogPost_Category");
- }
- );
问题:如果以上满足不了我们的需求,比如我需要再关系表中增加对当前关系的其它信息,比如isactive,只是个举例,实际博客分类中也许并不需要这个字段。那么在CategoryA.CategoryBlogPosts中我想选取IsActive为true的文章就很痛苦了。
根本原因在于这里的多对多映射叫做direct multi to multi直接隐藏了关系表,我自然想到了用两个一对多来实现,本来多对多就是这样来的。
那么映射就变成下面这样了:
- modelBuilder.Entity<BlogPost_Category>()
- .HasKey(it => it.BlogPostId)
- .HasKey(it => it.CategoryId);
- modelBuilder.Entity<BlogPost_Category>()
- .HasRequired(it => it.BlogPost)
- .WithMany(it=>it.BlogPostCategories)
- .HasForeignKey(it => it.BlogPostId).WillCascadeOnDelete(false);
- modelBuilder.Entity<BlogPost_Category>()
- .HasRequired(it => it.Category)
- .WithMany(c => c.BlogPost_Categorys)
- .HasForeignKey(it => it.CategoryId).WillCascadeOnDelete(false);
这里修改了之间关联的属性:
- public virtual ICollection<BlogPost_Category> BlogPostCategories { get; set; }
- public virtual IEnumerable<Category> Categories
- {
- get { return BlogPostCategories.Where(it => it.IsActive == true).Select(it => it.Category); }
- }
- public virtual ICollection<BlogPost_Category> BlogPost_Categorys { get; set; }
- public virtual IEnumerable<BlogPost> CategoryBlogPosts
- {
- get
- {
- return BlogPost_Categorys
- .Where(it => it.IsActive == true)
- .Select(it => it.BlogPost);
- }
- }
测试代码:
- [TestMethod]
- public void GetBlogPostsActivedInCategory_Test()
- {
- var cat = _aggBlogSiteService.GetCategory(2);
- cat.CategoryBlogPosts.
- ToList()
- .ForEach(p =>
- {
- Console.WriteLine(string.Format("ID:{0}\tTitle:{1}", p.ID,
- p.Title));
- p.Categories.ToList().ForEach(c => Console.WriteLine(
- string.Format("Categories:\ttitle:{0}\tisActive:{1}"
- , c.Title
- , c.BlogPost_Categorys
- .Single(pc => pc.BlogPostId == p.ID && pc.CategoryId == c.ID).IsActive)));
- });
- }
测试数据:
结果测试编译不通过,查了下资料,原来当BlogPostID和CategoryID一起做主键时就无法再作为外键,感觉没道理啊,相信将来Ef会改进,原因也不清楚,有时间得好好研究,另外推荐一本书:http://www.ppurl.com/2011/06/entity-framework-4-in-action.html
可惜我是忠实的CodeFirst Fans,等下个版本了。
新建另一个键当主键,不过显然是多余的,无所谓了(第三幅图中的ID就此由来~)。
测试结果:
最重要的是SQL脚本:
exec sp_executesql N'SELECT[Project2].[ID] AS [ID],[Project2].[Title] AS [Title],[Project2].[C1] AS [C1],[Project2].[ID1] AS [ID1],[Project2].[BlogPostId] AS [BlogPostId],[Project2].[CategoryId] AS [CategoryId],[Project2].[IsActive] AS [IsActive]FROM ( SELECT[Limit1].[ID] AS [ID],[Limit1].[Title] AS [Title],[Extent2].[ID] AS [ID1],[Extent2].[BlogPostId] AS [BlogPostId],[Extent2].[CategoryId] AS [CategoryId],[Extent2].[IsActive] AS [IsActive],CASE WHEN ([Extent2].[ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]FROM (SELECT TOP (1)[Extent1].[ID] AS [ID],[Extent1].[Title] AS [Title]FROM [dbo].[Category] AS [Extent1]WHERE [Extent1].[ID] = @p__linq__0 ) AS [Limit1]LEFT OUTER JOIN [dbo].[BlogPost_Category] AS [Extent2] ON [Limit1].[ID] = [Extent2].[CategoryId]) AS [Project2]ORDER BY [Project2].[ID] ASC, [Project2].[C1] ASC',N'@p__linq__0 int',@p__linq__0=2
呵呵,跟dudu的一样。。。Done
示例代码作者:today4king
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2007-07-19 OFFICE 大全简介(转自网络)