[原創] 擴展 Entity Farmework 支持隨機排序


在SQL 中,隨機排序是如下SQL語句:

1 Select * from user order by newid(); 

Linq to object 中隨機排序如下:

var users = new int[] {1,2,3,4,5};
Users.OrderBy(d=>Guid.NewId()); 

那么在EF中隨機排序是怎樣寫呢? 

var query = from a in context.Users
                    order by Guid.NewId()
                    select a;
Var users = query.ToList();

可以負責任的告訴你,以上代碼行不通。如果是EF4以前的版本,直接報錯。如果是EF以后的版本則會忽略排序。

那該怎樣才能讓EF支持隨機排序呢?

網上有一篇文章介紹Linq to SQL,http://www.cnblogs.com/Mirricle/archive/2007/08/16/858260.html ,代碼如下:

[Function(Name = "NEWID", IsComposable = true)]
public Guid NEWID()
{
     return ((Guid)(this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod()))).ReturnValue));
}
//使用
var customer = (from c in ctx.Customers orderby ctx.NEWID()).First();

在實踐過程中,發現這樣做起來很麻煩。首先需要在每個DBContext中寫這樣的方法。如果換一個項目又要寫一次。

有沒有簡潔的方法呢?

從SqlFunctions中找答案吧。SqlFunctions中添加了大部分SQL server中的函數,但遺憾的是沒有NewId,我們可以自己寫一個。

/// <summary>
/// Contains function stubs that expose SqlServer methods in Linq to Entities.
/// </summary>
public static class SqlFunctions
{
     /// <summary>
     /// Proxy for the function SqlServer.NEWID 
     /// </summary>
     [EdmFunction("SqlServer", "NEWID")]
     public static Guid NewId()
     {
         throw new NotSupportedException();
     }
}

然后為IQueryable<T>添加一個擴展方法:

public static IQueryable<T> OrderByRandom<T>(this IQueryable<T> source)
{
     return source.OrderBy(d => SqlClient.SqlFunctions.NewId());
}

最后寫個單元測試:

[TestMethod]
public void OrderByRandomTest()
{
     using (var context = IoC.Resolve<WitnessGodContext>())
     {
          var u1 = context.Users.OrderByRandom().FirstOrDefault();
          var u2 = context.Users.OrderByRandom().FirstOrDefault();
           Assert.AreNotEqual(u1.UserId, u2.UserId);
       }
}

通過單元測試。以下是通過QL Profile監視數據庫生成的SQL語句:

SELECT TOP (1) 
....
FROM ( SELECT 
   NEWID() AS [C1], 
   ....
   FROM [dbo].[User] AS [Extent1]
)  AS [Project1]
ORDER BY [Project1].[C1] ASC

后記

當然這種寫法有它的局限性,首先數據庫必須是SQL Server,不過目前使用EF,數據庫幾乎大都是SQL Server。大家可以放心使用,如果要支持多數據庫也是有辦法的。具體怎么做留待讀者自己去摸索吧!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM