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

我有一个字典声明如下:

private Dictionary<string, Expression<Func>> _orders = new Dictionary<string, Expression<Func>>() { {"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, IOrderedQueryable> 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 Query(Expression<Func> filter = null, Func<IQueryable, IOrderedQueryable> orderBy = null, bool noTracking = true) { IQueryable query = DbContext.Set(); if (filter != null) { query = query.Where(filter); } if (orderBy != null) query = orderBy(query); return noTracking ? query.AsNoTracking() : query; } 

但是当排序列不是string我获得以下exception

"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.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.d__0.MoveNext()"}

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

问题解决了

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

 public static class LinqExtension { public static IQueryable OrderBy(this IQueryable 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  orderByExp); return source.Provider.CreateQuery(resultExp); } } 

此外, Ivan Stoev提供的解决方案也起作用

字典定义是可以的 – 没有好的方法来声明它具有不同类型的值。

问题是Expression>定义为值类型属性生成了额外的Expression.Convert 。 要使其与EF一起使用,必须删除convert表达式,并且必须动态调用相应的Queryable方法。 它可以封装在这样的自定义扩展方法中:

 public static class QueryableExtensions { public static IQueryable OrderBy(this IQueryable source, Expression> 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(queryBody); } } 

并且您的场景中的用法可能如下所示:

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