使用带有条件过滤器的 Include() 连接两个表
Posted
技术标签:
【中文标题】使用带有条件过滤器的 Include() 连接两个表【英文标题】:Joining two tables using Include() with conditional filter 【发布时间】:2019-12-15 07:09:19 【问题描述】:我有现有代码要更新。我想加入另一个名为Table3
的表。
由于查询有一个 include 到 Table2
,我想添加另一个带有条件过滤器的 .Include
并避免左连接。
当我添加.include
和.where
时,我无法访问t3Id
。 Intellisense 只显示表格 Table3
而不是 Id
字段。
我错过了语法吗?谢谢。
Table1
有一个名为 t1Id
的密钥。
var query = (from e in ctx.Table1
.Include(r => r.Table2.Select(p => p.name))
.Include(rj => rj.Table3).Where(s => s.t1Id == t3Id)
select e).ToList();
Table1
将具有以下内容:
Id name
1 Joe
2 Mary
3 Harry
Table3
将具有以下内容:
t1Id title
3 staff
3 fulltime
预期结果:
1 Joe
2 Mary
3 Harry [2, staff, 3, fulltime]
由于 Harry 在映射表中有一条记录,他将有一个 Table3
行数组。
【问题讨论】:
是应该用于rj.Table3
的where子句
报错后,我不这么认为。我试图弄清楚如何计算 t1Id == t3Id 的 Table3 并返回每个 T1 行的所有 T3 数据。
我不清楚你要什么。您能否向我展示一个表 1、表 2 和表 3 的基本示例数据集以及您正在寻找的预期结果?
HI Train,刚刚添加了表格插图
使用 .net 4.7 和实体框架 6.3.0
【参考方案1】:
我刚刚注意到您的 EF 评论。 EF 属性Table1.Table3
应该已经加载了相关实体,而无需在使用包含时使用 where 子句。
试试这个扩展方法
public static IEnumerable<TEntity> GetAllIncluding(this params Expression<Func<TEntity, object>>[] includesProperties)
return includesProperties.Aggregate<Expression<Func<TEntity, object>>,
IQueryable<TEntity>>(_dbSet, (current, includeProperty)
=> current.Include(includeProperty));
使用功能
var data = table1.GetAllIncluding(x => x.Table2, y => y.Table3);
这应该已经加载了相关实体而无需过滤。
【讨论】:
【参考方案2】:最好尽可能使用Select
而不是Include
。 Select
将允许您仅查询您真正计划使用的属性,从而更快地将所选数据从数据库管理系统传输到您的进程。
例如,如果您查询“Schools with their Students”,Student
将有一个外键,其值等于 School 的主键。因此,如果您有 School 10,您现在将拥有其所有 5000 名学生的 SchoolId
,其值为 10。发送相同的值 10 超过 5000 次有点浪费。
查询数据时,始终使用 Select。仅当您计划更新获取的数据时才使用 Include。
您的查询(在方法语法中):
var result = dbContext.Table1
.Where(table1Element => ...) // only if you don't want all elements of Table1
.Select(table1Element => new
// only select the table1 elements that you plan to use:
Id = table1Element.Id,
Name = table1Element.Name,
// Select the items that you want from Table 2:
Table2Items = table1Element.Table2
.Where(table2Element => ...) // only if you don't want all table2 elements
.Select(table2Element => new
// Select only the properties of table2 you plan to use:
Id = table2Element.Id,
Name = table2Element.Name,
...
// the following not needed, you already know the value:
// Table1Id = table2Element.table1Id, // foreign key
)
.ToList(),
// Table3: your new code:
Table3Items = table1Element.Table3
.Select(table3Element => new
// again: only the properties you plan to use
Id = table3Element.Id,
...
// the following not needed, you already know the value:
// Table1Id = table3Element.table1Id, // foreign key
)
.ToList(),
);
您发现读者更容易看到他获得了哪些属性?如果其中一个表被展开,那么新的属性就不会在这个查询中被获取,毕竟:用户显然不需要新的属性。在此功能的规范中也没有描述它们。
注意:因为我使用了new
,所以我的类型是匿名类型。你只能在你的函数中使用它们。如果需要返回获取的数据,请将数据放在已知的类中:
.Select(table1Element => new Table1Class()
Id = table1Element.Id,
Name = table1Element.Name,
...
);
再次:考虑不要填写外键,因为您可能不会使用它们
【讨论】:
以上是关于使用带有条件过滤器的 Include() 连接两个表的主要内容,如果未能解决你的问题,请参考以下文章