linq 到实体,where 子句中的 where ? (内凡)
Posted
技术标签:
【中文标题】linq 到实体,where 子句中的 where ? (内凡)【英文标题】:linq to entities, a where in where clause? (inner where) 【发布时间】:2012-01-05 17:28:02 【问题描述】:我有一个表,该表具有一对多映射到一个表,该表具有多对多映射到另一个表。我想做以下事情:
var results = context.main_link_table
.Where(l => l.some_table.RandomProperty == "myValue" &&
l.some_table.many_to_many_table
.Where(m => m.RandomProperty == "myValue"));
我怎样才能做到这一点?第一部分可以工作,但是在没有“内部 WHERE”的情况下尝试它时,我无法访问 many_to_many_table 的属性,但“内部位置”显然无法编译。我基本上想实现类似下面的 SQL 查询:
SELECT * from main_link_table
INNER JOIN some_table AS t1 ON t1.association = main_link_table.association
INNER JOIN many_to_many_table AS t2 ON t2.association = some_table.association
WHERE t1.RandomProperty = 'MyValue' AND t2.RandomProperty = 'MyValue'
这看起来很简单,但我找不到在单行 linq 中实现它的方法 - 使用多行来实现所需的效果会返回太多结果,我最终不得不循环它们。我也尝试过类似的东西:
var results = main_link_tbl.Include("some_table.many_to_many_table")
.Where(l => l.some_table.many_to_many_table.<property>
== "MyValue")
但此时我无法选择 many_to_many_table 的属性,除非我添加一个 FirstOrDefault(),这会使效果无效,因为它不会搜索所有记录。
什么有效,但需要多行代码,并且在后台在 linq-to-entities 框架构建的 SQL 查询中返回太多结果:
var results = db.main_link_table.Include("some_table")
.Include("some_table.many_to_many_table")
.Where(s => s.some_table.RandomProperty
== "myValue")
.Select(s => s.some_table);
foreach(var result in results)
var match_data = result.Where(s => s.many_to_many_table.RandomProperty
== "myValue");
这段代码将返回 some_table 中与第一个 Where 条件匹配的所有行,然后应用下一个 Where 条件,而我显然只需要 many_to_many_table.RandomProperty 等于 myValue 的一行。
【问题讨论】:
【参考方案1】:如果您将内部的Where
更改为Any
,它应该可以工作:
var results = context.main_link_table
.Where(l => l.some_table.RandomProperty == "myValue" &&
l.some_table.many_to_many_table
.Any(m => m.RandomProperty == "myValue"));
【讨论】:
在 Many 端使用 ANY 的唯一问题是它不是真正的 WHERE 子句,它只是检测是否有任何记录满足条件。例如。如果您有 ANY many.balance > 0,如果至少 1 条记录的余额大于 0,则返回 true。因此它不会过滤掉余额为 0 的记录。请记住,ANY 仅返回一个布尔值来指示记录的存在,它实际上并没有过滤。 @CharlesOwen 而布尔值正是我们在这里所需要的,因为我们使用Any
作为Where
中的条件。
好吧,好心的先生,我提出了一个不同的场景,它不起作用。 Jon Skeet 的回答是总体上更好的解决方案,因为如果您有多个嵌套级别的连接,它可以进行更精细的控制。它可能已经解决了这个非常简单的问题,但通常查询并不那么简单。我已经处理了使用 LEFT JOIN 等连接 7 个或更多表的查询。您的解决方案不适用于此。
@CharlesOwen:如果您确实需要访问连接表中的数据,您只需要Where
而不是Any
。在这种情况下,正如 Jon 指出的那样,您绝对需要加入。如果您只使用连接表作为过滤器 - 就像这里的情况一样 - 那么“任何”就足够了。任何也可以嵌套。希望这能澄清一点。【参考方案2】:
如果你想加入,为什么不直接加入?
var query = from main in context.MainLinks
join t1 in context.Some on main.Association equals t1.Association
where t1.RandomProperty == "MyValue"
join t2 in context.ManyToMany on t1.Association equals t2.Association
where t2.RandomProperty == "MyValue"
select new main, t1, t2 ;
这应该完全实现您的 SQL 所做的......
【讨论】:
我认为这是一个比所选答案更好的解决方案,因为它展示了一个真正的 where 子句,允许您过滤掉许多表中不需要的记录。【参考方案3】:from link in db.main_link_table
join s in db.some_table on link.association1 = s.association
join m in db.many_to_many_table on link.association2 = m.association
where s.X = 'MyValue' AND m.Y = 'MyValue'
select m; // or s or link or both 3 as you want
【讨论】:
以上是关于linq 到实体,where 子句中的 where ? (内凡)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Func<T, string> lambda 动态构造 where 子句 - linq 到实体