强制LINQ to SQL在使用时使用RowNumber()而不是Top n .Skip(0)

时间:2011-08-03 20:02:11

标签: sql linq-to-sql

有没有办法强制LINQ to SQL避免在使用Skip(0)时使用TOP X?我有一个查询,对于每个分页结果都运行良好...除了第1页。我已经分析了查询和TOP子句的引入只是杀了它。我很困惑为什么会这样,但它确实如此。但是,使用1到10之间的RowNumber工作正常。

有没有办法强制LINQ to SQL避免在使用Skip(0)时使用TOP X?我有一个查询,对于每个分页结果都运行良好...除了第1页。我已经分析了查询和TOP子句的引入只是杀了它。我很困惑为什么会这样,但它确实如此。但是,使用1到10之间的RowNumber工作正常。

在我的WHERE子句中,罪魁祸首似乎是一个EXISTS条件。生成的SQL如下所示。在SQL管理器中,此查询运行正常并返回14个结果...但是,一旦我添加TOP 10(就像LINQ那样),它会超时。但是,如果我在where子句中注释EXISTS,那么问题就会消失。

SELECT 
    t0.ProtectiveOrderID, 
    t3.DocketID, 
    t3.DocketNumber AS CaseNumber, 
    t3.PartySuffix AS CaseNumberSuffix, 
    t5.FirstName AS RespondentNameFirst, 
    t5.MiddleName AS RespondentNameMiddle, 
    t5.LastName AS RespondentNameLast, 
    t5.NameSuffix AS RespondentNameSuffix,
    t4.FirstName AS ProtectedNameFirst, 
    t4.MiddleName AS ProtectedNameMiddle, 
    t4.LastName AS ProtectedNameLast, 
    t4.NameSuffix AS ProtectedNameSuffix, 
    t3.ChildNextFriendFirstName AS ChildNextFriendNameFirst, 
    t3.ChildNextFriendMiddleName AS ChildNextFriendNameMiddle, 
    t3.ChildNextFriendLastName AS ChildNextFriendNameLast, 
    t3.ChildNextFriendNameSuffix
FROM dbo.ProtectiveOrder AS t0
INNER JOIN (
SELECT MAX(t1.ProtectiveOrderID) AS value
FROM dbo.ProtectiveOrder AS t1
GROUP BY t1.DocketID
) AS t2 ON t0.ProtectiveOrderID = t2.value
LEFT OUTER JOIN dbo.Docket AS t3 ON t3.DocketID = t0.DocketID
LEFT OUTER JOIN dbo.Directory AS t4 ON t4.DirectoryID = t3.ProtectedPartyID
LEFT OUTER JOIN dbo.Directory AS t5 ON t5.DirectoryID = t3.SubjectID
WHERE 
(
    ((t4.LastName LIKE 'smith%') AND (t4.FirstName LIKE 'jane%')) 
    OR ((t5.LastName LIKE 'smith%') AND (t5.FirstName LIKE 'jane%')) 
    OR ((t3.ChildNextFriendLastName LIKE 'smith%') AND (t3.ChildNextFriendFirstName LIKE 'jane%')) 
    OR (
            -- ***************
            -- THIS GUY KILLS THE QUERY WHEN A TOP IS INTRODUCED IN THE TOP-LEVEL SELECT
            -- ***************
            EXISTS(
                    SELECT NULL AS EMPTY
                    FROM dbo.Child AS t6
                    WHERE (t6.LastName LIKE 'smith%') AND (t6.FirstName LIKE 'jane%') AND (t6.DocketID = t3.DocketID)
            )
    )
)
ORDER BY t3.DocketNumber

1 个答案:

答案 0 :(得分:1)

覆盖Skip方法,只需检查输入为零。对于任何值,但零调用原始跳过方法。零不要。

所以如果你修改了dynamic.cs中提供的Skip,你可以这样做:

    public static IQueryable Skip(this IQueryable source, int count)
    {
        if (count == 0)
        {
            return source;
        }
        if (source == null) throw new ArgumentNullException("source");
        return source.Provider.CreateQuery(
            Expression.Call(
                typeof(Queryable), "Skip",
                new Type[] { source.ElementType },
                source.Expression, Expression.Constant(count)));
    }