zoukankan      html  css  js  c++  java
  • 扩展 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。大家可以放心使用,如果要支持多数据库也是有办法的。具体怎么做留待读者自己去摸索吧!
  • 相关阅读:
    Flask从负到零的一周
    DOM(一):节点层次-Node类型
    错误处理(三):区分致命错误和非致命错误
    错误处理(二):常见错误类型
    错误处理(一)
    跨域(二)
    跨域(一)
    AJAX(四):XHR2支持的方法
    AJAX(三):GET与POST
    AJAX(二):HTTP头部信息
  • 原文地址:https://www.cnblogs.com/zcm123/p/3113945.html
Copyright © 2011-2022 走看看