I have a problem on using LinqToSQL with paging + dynamic sorting. These are my sample code.
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
This is the SQL script generated by LINQToSQL, which is only retrieve certain row of records.
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]
But if i implemented dynamic sort,
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
This is the SQL script generated this time,
SELECT [t0].[UserId], [t0].[UserName]
FROM [dbo].[User] AS [t0]
How come the paging control script is not generated and the sorting is gone?? Is that the way i implement dynamic sorting is wrong? or LinqToSQL did not support paging + dynamic sorting??
Help!!!
What you’re doing in your code will not work. However, I’m a bit surprised that LINQ to SQL doesn’t throw an exception.
The
OrderBymethod that you call inresult.OrderBy(expression), is theEnumerable.OrderBymethod and not theQueryable.OrderBymethod. You already noticed this, because the object it returns is anIEnumerable(Of User)and not anIQueryable(Of User). For this reason you are converting it to anIQueryable(Of User)by callingAsQueryable(). CallingAsQyeryablehowever, cannot work. The reason for this is that LINQ to SQL processes expression trees (what anIQueryablebasically is). And expression trees can be dynamically combined, as you already do withresult = result.Skip.Enumerablehowever, doesn’t work with expression trees, but with delegates, which are compiled method calls. While you can convert such a compiled method call to anIQueryable, LINQ to SQL cannot analyze it, because it still is compiled code (it would take introspection to do this, which only specialized tools as Reflector support). In this case LINQ to SQL probably ignored the complete order by part of your query, because it found a (compiled) method call it couldn’t process.So, you’re solution will only work when you do the following:
There is however -yet- another thing. You seem to loop through a set of
sortExpressions. While it is possible to append an already sorted collection, an already sorted collection must be called withresult.ThenByorresult.ThenByDescending. Calling it withresult.OrderBywill completely resort it; you will loose the initial sorting order.To make a long story short, perhaps you should try to build some sort of
EntitySorterobject that allows callers of your method to specify the sort order. Your service method could than look like this (sorry, it’s C#):I’ve written a blog about exactly this, again, it’s C#, but I think it will do exactly what you need.
Good luck.