c# – LINQ to Entities和LINQ to Objects处理强制转换的方式不
我最近加入了一个项目,其中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); } } 解决方法
表达树顾名思义就是关于做某事的表达.你可以访问表达式并将它们解释为你自己的业务,或者像lambda表达式一样,你可以编译它们并作为委托调用.
当您将表达式传递给Linq to Entities中的orderby方法时,Linq将访问实体,并且在您的情况下将生成“Int32 to Object”异常,因为它被解释为成为列名的MemberInfo用于数据库查询.但是当你将它用作Func委托时,它无法被翻译,它将被调用为orderby方法的排序算法中的委托. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |