使用linq指定子查询的子查询的正确方法

时间:2012-06-05 14:10:55

标签: c# linq entity-framework

results = (from r in results 
where r.Buildings.Any(x=>x.StructuralElements.Any(s=>s.VALUE == Model.Bedrooms.ToString() && s.CATEGORY=="RM"))
select r);

我想我在这里错过了加入。但也许他们暗示了?执行运行这么久我无法做一个手表来评估生成的查询表达式

1 个答案:

答案 0 :(得分:0)

此查询中的最大问题是:

--@p1 = Models.Bedrooms.ToString()
--@p2 = "RM"
SELECT * FROM Results r WHERE EXISTS
    (SELECT x.* FROM Results tr JOIN Buildings x ON tr.SomeID=x.SomeID WHERE tr.ID = r.ID AND EXISTS
        (SELECT s.* FROM StructuralElements s JOIN Buildings tx ON tx.OtherID = s.OtherID WHERE tx.ID=x.ID AND s.VALUE = @p1 AND s.Category = @p2))

你明白为什么会这么糟糕吗?对于每个Result,您正在运行子查询(它本身正在运行子查询)。由于这些嵌套的子查询,当您开始在根级别(结果和建筑物)添加内容时,这将是时间/处理的指数增长。最好的办法是在完成后使用连接并获得不同的r值。 SQL希望如下:

SELECT DISTINCT 
    r.* 
FROM
    Results r
    INNER JOIN Buildings x ON x.SomeID = r.SomeID
    INNER JOIN StructuralElements s ON s.OtherID = r.OtherID
WHERE
    s.VALUE = @p1 AND s.CATEGORY = @p2

这将起作用的原因是,当您加入时,如果有多个要加入,它将复制原始行。下图显示

IDs
R     X     S
1     -     -
Join X
1     1     -
1     2     -
1     3     -
Join S
1     1     1
1     1     2
1     2     5
1     2     6

假设S=2S=6符合您的条件,则会返回(R,X,S表格)行1,1,21,2,6。在这种情况下,只获得不同的r只会返回R=1,这正是您要完成的任务。使用EF,关系已经存在,因此您不需要做任何额外的事情,只需引用您尝试过滤的列:

results =  (from r in results
            from x in r.Buildings
            from s in x.StructuralElements
            where s.VALUE == Model.Bedrooms.ToString() && s.CATEGORY=="RM"
            select r).Distinct();

这是PlayMany运算符(它将一个集合并将子集合展平为一个集合)。