摘要:讓ODATA傳回的結果依照程式碼的反向排序
雖說ODATA是讓排序與選擇的控制權更簡單的轉移到Client端上,
但你知道,有時會有一些特殊的需求...
這邊遇到的例子是客戶不想下orderby,但他希望取得資料的排序永遠可以從新到舊,且可以使用ODATA的$top與$skip。
其實另外寫API也未嘗不可,不過遇到這個問題也蠻有趣的。
首先,由新到舊通常的做法是用建立時間或Id序數做反向排序,寫法很單純:
[Queryable]
public IQueryable<Book> GetBooks()
{
return db.Books.OrderByDescending(book => book.Id);
}
db是一個DbContext,資料是從SQL Server撈的。
在不使用ODATA的情況下,出來的資料很正常:
[{"ID":4,"Name":"三隻小豬"},{"ID":3,"Name":"白雪公主"},{"ID":2,"Name":"睡美人"},{"ID":1,"Name":"小紅帽"}]
但使用ODATA,加上$top=2,撈出前兩筆時,資料好像怪怪的:
[{"ID":1,"Name":"小紅帽"},{"ID":2,"Name":"睡美人"}]
刪的不是全撈的前兩筆,順序也沒有依照全撈的順序。
檢查一下SQL指令,發現變成這樣:
SELECT TOP (2)
[Extent1].[Id],
[Extent1].[Name]
FROM [db].[Book] AS [Extent1]
ORDER BY [Extent1].[Id] ASC
雖稍有簡化,但重點在於.......ORDER BY 被改成了ASC!
實驗了一陣子,這邊說說最簡單的解決方法:
[Queryable(EnsureStableOrdering = false)]
public IQueryable<Book> GetBooks()
{
return db.Books.OrderByDescending(book => book.Id);
}
只有第一行在宣告Queryable屬性時有差,就這樣?
沒錯,就這樣。這樣ODATA就不會去更動原本的排序了,不過應該是有些副作用,我還沒詳測就是了。
另外如果是使用ODataQueryOptions的ApplyTo的話,可以套用settings:
public IQueryable<Book> GetBooks(ODataQueryOptions opts)
{
return (IQueryable<Book>)opts.ApplyTo(
db.Books.OrderByDescending(book => book.Id),
new ODataQuerySettings() { EnsureStableOrdering = false });
}