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 到实体

自动将一些 Where 子句添加到 Linq 表达式树

具有 LINQ 的实体框架在 WHERE 子句中使用 CONTAINS 非常慢且具有大整数列表

实体框架 Linq 查询:.Where 链 vs &&

具有许多表、左外连接和 where 子句的 LINQ 查询

Linq to entity 没有生成 where 子句