LinqToSQL + пейджинг + динамическая сортировка? - PullRequest
1 голос
/ 11 марта 2010

У меня проблема с использованием LinqToSQL с подкачкой + динамическая сортировка. Это мой пример кода.

Using db As New MyDataContext(connectionString)
      db.Log = new DebuggerWritter
      Dim result = db.User.OrderBy(Function(u) u.UserId)

      result = result.Skip((pageNo - 1) * pageSize).Take(pageSize)      
End Using

Это сценарий SQL, сгенерированный LINQToSQL, который извлекает только определенную строку записей.

SELECT [t1].[UserId], [t1].[UserName]
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[UserId]) AS [ROW_NUMBER], [t0].[UserId], [t0].[UserName]
    FROM [dbo].[User] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]

Но если я реализовал динамическую сортировку,

Using db As New MyDataContext(connectionString)
      db.Log = new DebuggerWritter
      Dim result = db.User

      For Each s In sortExpressions

          Dim expression As Func(Of User, Object) = Function(u) u.[GetType]().GetProperty(s.propertyName).GetValue(u, Nothing)

          Select Case s.SortOrder
               Case SortExpression.SortDirection.Ascending
                    result = result.OrderBy(expression).AsQueryable
               Case SortExpression.SortDirection.Descending
                    result = result.OrderByDescending(expression).AsQueryable
          End Select
      Next

      result = result.Skip((pageNo - 1) * pageSize).Take(pageSize)  
End Using

Это сценарий SQL, сгенерированный на этот раз,

SELECT [t0].[UserId], [t0].[UserName]
FROM [dbo].[User] AS [t0]

Почему сценарий управления подкачкой не сгенерирован, а сортировка прекращена? Это способ, которым я реализую динамическую сортировку, неправильно? или LinqToSQL не поддерживает подкачку + динамическую сортировку ?? Помогите !!!

1 Ответ

1 голос
/ 11 марта 2010

То, что вы делаете в своем коде, не будет работать. Однако я немного удивлен, что LINQ to SQL не вызывает исключения.

Метод OrderBy, который вы вызываете в result.OrderBy(expression), является методом Enumerable.OrderBy, а не методом Queryable.OrderBy. Вы уже заметили это, потому что объект, который он возвращает, это IEnumerable(Of User), а не IQueryable(Of User). По этой причине вы конвертируете его в IQueryable(Of User), вызывая AsQueryable(). Однако, вызов AsQyeryable не может работать. Причина этого в том, что LINQ to SQL обрабатывает деревья выражений (что в сущности означает IQueryable). И деревья выражений могут быть динамически объединены, как вы уже делаете с result = result.Skip. Enumerable однако, не работает с деревьями выражений, но с делегатами, которые являются вызовами скомпилированных методов. Хотя вы можете преобразовать такой вызов скомпилированного метода в IQueryable, LINQ to SQL не может его проанализировать, поскольку он все еще является скомпилированным кодом (для этого потребуется самоанализ, который поддерживают только специализированные инструменты, такие как Reflector). В этом случае LINQ to SQL, вероятно, проигнорировал полный порядок по части вашего запроса, поскольку обнаружил (скомпилированный) вызов метода, который не может быть обработан.

Итак, ваше решение будет работать только тогда, когда вы выполните следующее:

Dim expression As Expression(Of Func(Of User, [ExpectedKeyHere]) = _
   ...  creation of the expression here ...

Select Case s.SortOrder
    Case SortExpression.SortDirection.Ascending
        result = result.OrderBy(expression)
    Case SortExpression.SortDirection.Descending
        result = result.OrderByDescending(expression)
End Select

Однако есть еще одна вещь. Кажется, вы просматриваете набор sortExpressions. Хотя можно добавить уже отсортированную коллекцию, уже отсортированная коллекция должна вызываться с помощью result.ThenBy или result.ThenByDescending. Вызов с result.OrderBy полностью прибегнет к нему; Вы потеряете первоначальный порядок сортировки.

Короче говоря, возможно, вам следует попытаться создать какой-то объект EntitySorter, который позволяет вызывающим объектам вашего метода указывать порядок сортировки. Ваш метод обслуживания может выглядеть следующим образом (извините, это C #):

public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
    Condition.Requires(sorter, "sorter").IsNotNull();

    using (var db = ContextFactory.CreateContext())
    {
        IOrderedQueryable<Person> sortedList =
            sorter.Sort(db.Persons);

        return sortedList.ToArray();
    }
}

Я написал блог именно об этом , опять же, это C #, но я думаю, что он будет делать именно то, что вам нужно.

Удачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...