C# 实体框架linq orderby函数
我不熟悉实体框架和linq。我正在使用asp.NETMVC5和C。 我编写了一个具有动态排序的查询,如下所示:C# 实体框架linq orderby函数,c#,linq,function,asp.net-mvc-5,entity-framework-6,C#,Linq,Function,Asp.net Mvc 5,Entity Framework 6,我不熟悉实体框架和linq。我正在使用asp.NETMVC5和C。 我编写了一个具有动态排序的查询,如下所示: public static IEnumerable<T> OrderByDynamic<T>(this IEnumerable<T> source, string propertyName, bool Ascending) { if (Ascending) return source.OrderBy(x => x.Get
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));
}
当排序在表的列上时,这段代码可以正常工作,但我需要使用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查询?您的解决方案引入了几个问题: 您可以按名称按属性排序,希望所排序的对象具有此属性。如果您的对象没有此属性怎么办? SQL不理解像GetProperty这样的函数,所以这种排序必须在本地内存AsEnumerable中完成,而不是在更快的SQL server AsQueryable中完成。 您可以使用存储过程进行排序。 前两个问题可以通过Func keySelector更改参数propertyName轻松解决: 这种方法的优点是,如果您试图按不存在的属性排序,编译器会抱怨。除此之外,此OrderBy还可以作为可查询项执行;它可以由数据库而不是在本地内存中执行 使用字符串来选择所需的属性确实不是一个好主意 如果您输入错误,您只能在运行时检测到。此外:如果您知道在代码开发期间为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);
只有最终结果中的酒店才会与StoredProcess的结果一起传输到本地内存。他们只为你在最终结果中使用的酒店打过电话
但是,排序是在本地内存中完成的。如果您还希望在数据库端执行此排序,则必须创建一个新的存储过程,在执行排序之前调用另一个存储过程。感谢Harald 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);
}
我在第页找到:
使用函数进行排序是一种不好的做法。您应该首先优化查询。提供您的函数getHotelMinPrice\u cap,以便提供优化方式。从room\u price中选择minroom\u price.price,room_definition其中room_price.roomDef_id=room_definition.id和room_definition.Hotel_id=Hotel_id和room_definition.capacity=容量和room_price.start_date介于输入日期和退出日期之间或room_price.stop_date介于输入日期和退出日期之间我请求的sql函数。该函数返回我指定的minroom_price.price在之前的评论中提到。房间价格已加入房间定义,房间定义已加入酒店。感谢您的回答。我不知道你写的“StoredProcedureValue”和“CallStoredprocedure”是什么!它们是什么??我想使用一个名为“getHotelMinPrice_cap”的函数,因为您似乎不熟悉匿名类型。在Where语句中,我获取了Hotels集合,并从该集合中的每个项目(我方便地用标识符hotel标识)创建了一个匿名类的新对象,该对象有两个属性:StoredProcedureValue和hotel。我不知道如何获得存储过程的值,所以我只调用了一个函数,该函数将按照通常的方式执行。Orderby将此匿名类型作为输入
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);
_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();
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);
}