您的位置:首页 > 其它

扩展 Entity Farmework 支持随机排序

2013-06-02 15:24 465 查看
在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。大家可以放心使用,如果要支持多数据库也是有办法的。具体怎么做留待读者自己去摸索吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐