我最近加入了一个项目,其中Sort方法有条件地将lambda表达式传递给LINQ查询以定义应该对哪个属性进行排序.问题是lambda表达式是在Func< TEntity,Object>中传递的.而不是表达式< Func< TEntity,Object>>因此,排序发生在内存而不是数据库中(因为调用了带有IEnumerable的OrderBy的重载).这是SortWithDelegate中的版本(见下文).
当我使用表达式< Func< TEntity,Object>> (参见下面的SortWithExpression)然后,当在orderBy参数中传递字符串属性时,在数据库中正确完成排序.但是,当我尝试使用Expression< Func< TEntity,Object>>对整数(或日期时间)进行排序时我收到以下错误:
无法将类型“system.int32”强制转换为“System.Object”类型. LINQ to Entities仅支持转换EDM原语或枚举类型.
为了避免这种情况,我必须将整数或日期时间字段包装在匿名类型内部,如下所示:orderByFunc = sl => new {sl.ParentUnit.Id};.我知道我需要这样做,因为Func的返回类型是Object.但是,我不明白为什么在使用LINQ to Entities提供程序而不是LINQ to Objects提供程序时需要执行此操作?
void Main() { var _context = new MyContext(); string sortProperty = "Id"; bool sortAscending = false; IQueryable<Qualification> qualifications = _context.Qualifications.Include(q => q.ParentUnit); qualifications = SortWithExpression(sortProperty,sortAscending,qualifications); qualifications.Dump(); } private static IQueryable<Qualification> SortWithDelegate(string orderBy,bool sortAscending,IQueryable<Qualification> qualificationsQuery) { Func<Qualification,Object> orderByFunc; switch (orderBy) { case "Name": orderByFunc = sl => sl.Name; break; case "ParentUnit": orderByFunc = sl => sl.ParentUnit.Name; break; case "Id": orderByFunc = sl => sl.ParentUnit.Id; break; case "Created": orderByFunc = sl => sl.Created; break; default: orderByFunc = sl => sl.Name; break; } qualificationsQuery = sortAscending ? qualificationsQuery.OrderBy(orderByFunc).AsQueryable() : qualificationsQuery.OrderByDescending(orderByFunc).AsQueryable(); return qualificationsQuery; } private static IQueryable<Qualification> SortWithExpression(string orderBy,IQueryable<Qualification> qualificationsQuery) { Expression<Func<Qualification,Object>> orderByFunc; switch (orderBy) { case "Name": orderByFunc = sl => sl.Name; break; case "ParentUnit": orderByFunc = sl => sl.ParentUnit.Name; break; case "Id": orderByFunc = sl => new {sl.ParentUnit.Id}; break; case "Created": orderByFunc = sl => new {sl.Created}; break; default: orderByFunc = sl => sl.Name; break; } qualificationsQuery = sortAscending ? qualificationsQuery.OrderBy(orderByFunc) : qualificationsQuery.OrderByDescending(orderByFunc); return qualificationsQuery; }
我以为我会为这个问题添加自己的解决方案.为了避免装箱int和datetime,我在IQueryable< T>上创建了一个通用的扩展方法.我传入lambda表达式来指示sort字段,以及一个布尔值,指示排序顺序是否应该升序:
public static IQueryable<TSource> OrderBy<TSource,TResult>(this IQueryable<TSource> query,Expression<Func<TSource,TResult>> func,bool sortAscending) { return sortAscending ? query.OrderBy(func) : query.OrderByDescending(func); } private static IQueryable<Qualification> Sort(string orderBy,IQueryable<Qualification> qualificationsQuery) { switch (orderBy) { case "Name": return qualificationsQuery.OrderBy(sl => sl.Name,sortAscending); case "ParentUnit": return qualificationsQuery.OrderBy(s1 => s1.ParentUnit.Name,sortAscending); default: return qualificationsQuery.OrderBy(sl => sl.Name,sortAscending); } }
解决方法
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。