在实体框架中加入 3 个一对多表
Posted
技术标签:
【中文标题】在实体框架中加入 3 个一对多表【英文标题】:Join 3 One to Many Tables in Entity Framework 【发布时间】:2017-02-06 20:42:02 【问题描述】:我有 2 个表,每个表与之间的表具有一对多关系,并且表之间的表具有 2 个其他表的 id
dbo.Posts dbo.Posts_Categories dbo.Categories
-ID -ID -ID
-Title -PostID -Name
-CategoryID
我期望的结果是:
Title = post1 Categories = web,mobile,desktop
Title = post2 Categories = app,game
...
我知道如何在 sql 中使用 Stuff 函数和 For Xml Path 进行查询,但我不知道如何在实体框架中执行此操作!
任何关于如何以这种方式工作的建议或书籍都可能有所帮助!
编辑:添加了 EF 类:
public class Post : ReportingBase
public Post()
[Required, MaxLength(500)]
public string Title get; set;
[Required, MaxLength(500)]
public string Address get; set;
[Required]
public string Body get; set;
[Required, MaxLength(500)]
public string Tags get; set;
[Required]
public int Visit get; set;
public virtual ICollection<Post_Category> Posts_Categories get; set;
public virtual ICollection<Post_AttachedFile> Posts_AttachedFiles get; set;
[ForeignKey("Image")]
public virtual int? ImageID get; set;
public virtual Image Image get; set;
public class Post_Category
public Post_Category()
[Key, Column(Order = 0)]
public int PostID get; set;
[Key, Column(Order = 1)]
public int CategoryID get; set;
public virtual Post Post get; set;
public virtual Category Category get; set;
public class Category : EntityBase
public Category()
[Required, MaxLength(50)]
public string Name get; set;
[Required, MaxLength(150)]
public string Address get; set;
public int? ParentID get; set;
public virtual ICollection<Post_Category> Posts_Categories get; set;
提前谢谢你
编辑:根据@IvanStoev 的回答,我做了以下操作:
List<P> p = context.Posts.Select(post => new
Title = post.Title,
Categories = post.Posts_Categories.Select(pc => pc.Category.Name).ToList()
).ToList();
并创建了一个名为 P 的类:
public class P
public string Title get; set;
public List<string> Categories get; set;
但它不能正常工作,问题是如何返回结果。
【问题讨论】:
好吧,为了帮助进行 EF 查询,我们需要 EF 模型(类、流式配置等)而不是 db 表。 我添加了实体@IvanStoev 您可以删除所有那些空的构造函数 - 只会使您的代码变得模糊。另外,在定义一对多关系时,建议使用ICollection<Type>
而不是List<Type>
。
【参考方案1】:
由于所谓的navigation properties 的概念,在 EF 中它甚至比在 SQL 中更容易。您只需要了解基本的 LINQ 查询语法,然后按照它们(导航)即可获取所需的数据。例如:
var result = db.Posts
.Select(post => new
Title = post.Title,
Categories = post.Posts_Categories
.Select(pc => pc.Category.Name)
.ToList()
)
.ToList();
结果是具有string
Title 属性和包含相关类别名称的List<string>
Categories 属性的匿名类型列表。
【讨论】:
它似乎可以工作,但我不知道如何退货!我的意思是我不知道什么是结果类型@IvanStoev 只需创建一个类 -public class SomeClass public string Title get; set; public List<string> Categories get; set;
并使用 post => new SomeClass ...
。结果类型将为List<SomeClass>
。啊,我看到了你的编辑 - 你快到了,忘了在 new
之后添加 P
:)
这是错误的代码。你不应该像那样调用.ToList()
两次——它会导致两个单独的查询,如果你使用.Include()
的导航属性,你可以在查询中做到这一点。此外,EF 会正确索引您要加入的外键。否决先生
@KellenStuart 这是针对 EF Core 2.x 先生的。那时,EF Core 需要内部 ToList()
调用来选择应用优化以实际避免 N + 1 个查询。没有“单查询”模式,它是在 3.0 中引入的。没有它,他们用它执行了 N + 1 个查询——只有 2 或 3 个(类似于 5.x “拆分查询”模式:-) EF Core 团队每次发布都改变概念并打破现有的不是我的错以一种或另一种方式编码。
@IvanStoev 如果是这种情况,问题应该用
【参考方案2】:
您可以使用 Linqpad(软件)来熟悉 Linq 查询,它通过连接到数据库为您构建 lambda 表达式并提供输出以进行交叉验证。
下面的一个是用于连接您提到的表的 lambda 表达式。
p - Post
pc - post_categories
c - categories
代码:
Posts.Join(Post_Categories, p => p.ID, pc => pc.ID, ( p, pc) => new p = p, pc = pc)
.Join(Categories, pcc => pcc.pc.CategoryID, c => c.ID, ( pcc, c) => new pcc = pcc, c = c)
.Select(p.Title)
.Select(c.Name)
【讨论】:
【参考方案3】:您应该使用.Include()
来任何加入 EF Core。
我想出了一个简单的例子:一个人可以养很多条狗。
public class Person
public Guid Id get; set;
public ICollection<Dog> Dogs get; set; // One Person can have many Dogs
public class Dogs
public Guid Id get; set;
public Guid PersonId get; set;
创建模型后生成迁移。在这个答案中不讨论如何做到这一点。
以下是您如何使用.Include()
加入两个不同的表:
public class PersonRepository : RepositoryBase
public IEnumerable<Person> FetchPeopleWithManyDogs()
return DatabaseContext.Person
.Include(x => x.Dogs)
.Where(x => x.Dogs.Count() > 1).ToList();
【讨论】:
以上是关于在实体框架中加入 3 个一对多表的主要内容,如果未能解决你的问题,请参考以下文章
mybatismybatis多表联查,存在一对多关系的,实体中使用List作为字段接收查询结果的写法