我在使用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
这是LINQToSQL生成的SQL脚本,它只检索某些记录行。
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不支持分页+动态排序? 帮助!
答案 0 :(得分:1)
您在代码中执行的操作无效。但是,我对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();
}
}
I've written a blog about exactly this,再次,它是C#,但我认为它将完全符合您的需求。
祝你好运。