2017-08-24 56 views
1

我是实体框架和linq的新手。我正在使用asp.net mvc 5和C#。 我写的动态排序查询,如下所示:实体框架linq orderby函数

public static IEnumerable<T> OrderByDynamic<T>(this IEnumerable<T> source, string propertyName, bool Ascending) 
{ 
    if (Ascending) 
     return source.OrderBy(x => x.GetType().GetProperty(propertyName).GetValue(x, null)); 
    else 
     return source.OrderByDescending(x => x.GetType().GetProperty(propertyName).GetValue(x, null)); 
    } 

,并在我的仓库,我可以写:

string sortExpr = "name"; 
_objDB.hotels.Where(s => (s.city_id = 1)) 
      .OrderByDynamic(sortExpr, Ascending).ToList(); 

此代码工作正常排序是在一个表中的列时,但我需要通过SQL函数进行排序。我进入功能到.edmx模型下面的代码

[EdmFunction("hotelReservation.Core.Data", "getHotelMinPrice_cap")] 
public static int getHotelMinPrice_cap(int Hotel_id, int capacity, DateTime enter_date, DateTime exit_date) 
{ 
    throw new NotSupportedException("Direct calls are not supported."); 
} 

和我的SQL的选择是一样的东西:

select * 
from hotel 
where city_id = 1 
order by dbo.getHotelMinPrice_cap(hotel.id,1,'2001-01-01', '2021-01-01') 

我怎么能写在LINQ动态排序的最后一个SQL查询?

+0

为了用一个函数是一个不好的做法。您应该首先优化您的查询。提供你的函数'getHotelMinPrice_cap',以便提供优化方式。 –

+0

SELECT MIN(room_price.price) 从room_price,room_definition 其中room_price.roomDef_id = room_definition.ID 和room_definition.Hotel_id = HOTEL_ID和room_definition.capacity =容量 之间enter_date和exit_date或room_price.stop_date之间(room_price.start_date enter_date和exit_date) – saeedeh

+0

我正在询问sql函数。 –

回答

0

由于哈拉尔Coppoolse的答案 我终于做到了这样:

_objDB.hotels .Select(h=> new { id= h.id, name=h.name, star=h.star, 
        minPrice1 = hotel.getHotelMinPrice_cap(h.id, 1, model.date_check_in, model.date_check_out)}) 
.Where(s => (s.city_id = 1)) 
.OrderByDynamic(sortExpr, Ascending).ToList(); 

在这种情况下,我可以选择sortExpr = minPrice1;,它将由SQL函数来排序。

我也改变了OrderByDynamic功能波纹管:

public static IQueryable<T> OrderByDynamic<T>(this IQueryable<T> q, string SortField, bool Ascending) 
     { 
      var param = Expression.Parameter(typeof(T), "p"); 
      var prop = Expression.Property(param, SortField); 
      var exp = Expression.Lambda(prop, param); 
      string method = Ascending ? "OrderBy" : "OrderByDescending"; 
      Type[] types = new Type[] { q.ElementType, exp.Body.Type }; 
      var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp); 
      return q.Provider.CreateQuery<T>(mce); 
     } 

我网页上找到: https://stackoverflow.com/a/7265354/8509940

1

您的解决方案引入了几个问题:

  • OrderBy通过名称的属性,希望您订购的对象具有这种性质。如果你的对象没有这个属性呢?
  • SQL不理解像GetProperty()这样的函数,所以这个排序必须在本地内存(AsEnumerable)中完成,而不是更快的SQL服务器(AsQueryable)。
  • 您可以使用存储过程进行排序。

    public static IEnumerable<T, TKey> OrderByDynamic<T>(this IEnumerable<T> source, 
        Func<T, TKey> keySelector, System.ComponentModel.ListSortDirection sortDirection) 
    { 
        if (sortDirection == ListSortDirection.Ascending) 
         return source.OrderBy(keySelector); 
        else 
         return source.OrderByDescending(keySelector); 
    } 
    

    用法是这样的::

前两个问题可以很容易地通过一个Func<TSource, TKey> keySelector改变参数propertyName来解决

var result = Students.OrderByDynamis(student => student.Name, ListSortDirection.Ascending); 

这种方法的好处是,你的如果您尝试通过不存在的属性进行排序,编译器会发出抱怨。此外OrderBy可以执行AsQueryable;它可以由您的数据库执行,而不是在本地内存中执行。

使用字符串来选择您想要的属性是一个坏主意。

如果您输入错误,您只能在运行时检测到此错误。此外:如果您知道在编写代码的过程中需要输入的字符串为propertyName,您还知道要分类的对象类型,因此您可以改为编写keySelector

你的第二个问题是调用存储过程作为排序顺序。这是比较容易解决的,如果你首先调用的返回值的存储过程,然后顺序:

var result = Hotels.Where(hotel => hotel...) 
    .Select(hotel => new 
    { 
     StoredProcedureValue = CallStoredprocedure(hotel,...), 
     Hotel = hotel, 
    }) 
    .AsEnumerable() // bring the result to local memory 
    .Orderby(item => item.StoredProcedureValue) 
    .Select(item => item.Hotel); 

只有酒店,将在您的最终结果传送到本地内存,搭配的结果一起存储过程。他们只被要求在最终结果中使用的酒店。

但是,排序是在本地内存中完成的。如果您还希望在数据库端完成此排序,则必须创建一个新的存储过程,在执行排序之前调用其他存储过程。

+0

非常感谢您的答案。我不知道你写的'StoredProcedureValue'和'CallStoredprocedure'是什么!他们是什么?我想使用一个名为'getHotelMinPrice_cap'的函数 – saeedeh

+0

看来你对匿名类型并不熟悉。在Where语句中,我从Collection中的每个项目收集'Hotels',并使用标识符'hotel'方便地识别,我创建了一个匿名类的新对象,具有两个属性:'StoredProcedureValue'和' Hotel'。我不知道你是如何得到存储过程的价值的,所以我只是调用一个可以像你平常那样做的函数。 Orderby以匿名类型作为输入 http://geekswithblogs.net/BlackRabbitCoder/archive/2012/06/21/c.net-little-wonders-the-joy-of-anonymous-types.aspx –