x.Name}, -6ren">
gpt4 book ai didi

c# - 如何在 Entity Framework 中创建动态订单

转载 作者:行者123 更新时间:2023-12-01 22:56:49 25 4
gpt4 key购买 nike

我有一个这样声明的字典:

private Dictionary<string, Expression<Func<Part, object>>> _orders = new Dictionary<string, Expression<Func<Part, object>>>()
{
{"Name", x => x.Name}, //string
{"Code", x => x.Code}, //string
{"EnterPrice", x => x.EnterPrice}, //decimal
{"ExitPrice", x => x.ExitPrice}, //decimal
{"IsActive", x => (bool)x.Active }, //bool
{"Quantity", x => x.Quantity}, //decimal
{"Reserved", x => x.Reserved}, //decimal
};

我尝试使用以下代码引入数据:

    NameValueCollection filter = HttpUtility.ParseQueryString(Request.RequestUri.Query);
string sortField = filter["sortField"];
string sortOrder = filter["sortOrder"];
Func<IQueryable<Part>, IOrderedQueryable<Part>> orderBy = x => x.OrderBy(p => p.Id);
if (!string.IsNullOrEmpty(sortField) && _orders.ContainsKey(sortField))
{
bool sortMode = !string.IsNullOrEmpty(sortOrder) && sortOrder != "desc";
if (sortMode)
{
orderBy = x => x.OrderBy(_orders[sortField]);
}
else
{
orderBy = x => x.OrderByDescending(_orders[sortField]);
}
}
return Ok(this.DbService.Query(null, filterQuery));

Query方法是:

public IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, bool noTracking = true)
{

IQueryable<TEntity> query = DbContext.Set<TEntity>();
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null) query = orderBy(query);
return noTracking ? query.AsNoTracking() : query;
}

但是当排序列不是string时我得到以下异常

"Unable to cast the type 'System.Boolean' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.","ExceptionType":"System.NotSupportedException","StackTrace":" at System.Web.Http.ApiController.<InvokeActionWithExceptionFilters>d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()"}

我认为字典声明和/或初始化是错误的,因为如果我没有通过浏览器设置任何排序,那么默认顺序将是 x=>x.Id (声明为内联)并且即使 Id 它也不会崩溃是 long 。我可以用不同的方式声明字典来解决我的问题吗?

问题已解决

我删除了字典,并添加了以下扩展,它接收字段名称和排序模式作为参数

public static class LinqExtension
{
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, bool ascending = true)
{
var type = typeof(T);
var parameter = Expression.Parameter(type, "p");
PropertyInfo property;
Expression propertyAccess;
if (ordering.Contains('.'))
{
// support to be sorted on child fields.
String[] childProperties = ordering.Split('.');
property = type.GetProperty(childProperties[0]);
propertyAccess = Expression.MakeMemberAccess(parameter, property);
for (int i = 1; i < childProperties.Length; i++)
{
property = property.PropertyType.GetProperty(childProperties[i]);
propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
}
}
else
{
property = typeof(T).GetProperty(ordering);
propertyAccess = Expression.MakeMemberAccess(parameter, property);
}
var orderByExp = Expression.Lambda(propertyAccess, parameter);
MethodCallExpression resultExp = Expression.Call(typeof(Queryable),
ascending ? "OrderBy" : "OrderByDescending",
new[] { type, property.PropertyType }, source.Expression,
Expression.Quote(orderByExp));
//return source.OrderBy(x => orderByExp);
return source.Provider.CreateQuery<T>(resultExp);
}
}

Ivan Stoev 提供的解决方案也有效

最佳答案

字典定义没问题 - 没有好的方法来声明它具有不同类型的值。

问题是 Expression<Func<T, object>>定义生成额外的 Expression.Convert 对于值类型属性。要使其与 EF 一起使用,必须删除转换表达式并对应 Queryable方法必须动态调用。它可以封装在自定义扩展方法中,如下所示:

public static class QueryableExtensions
{
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, Expression<Func<T, object>> keySelector, bool ascending)
{
var selectorBody = keySelector.Body;
// Strip the Convert expression
if (selectorBody.NodeType == ExpressionType.Convert)
selectorBody = ((UnaryExpression)selectorBody).Operand;
// Create dynamic lambda expression
var selector = Expression.Lambda(selectorBody, keySelector.Parameters);
// Generate the corresponding Queryable method call
var queryBody = Expression.Call(typeof(Queryable),
ascending ? "OrderBy" : "OrderByDescending",
new Type[] { typeof(T), selectorBody.Type },
source.Expression, Expression.Quote(selector));
return source.Provider.CreateQuery<T>(queryBody);
}
}

您的场景中的用法可能是这样的:

if (!string.IsNullOrEmpty(sortField) && _orders.ContainsKey(sortField))
orderBy = x => x.OrderBy(_orders[sortField], sortOrder != "desc");

关于c# - 如何在 Entity Framework 中创建动态订单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39685787/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com