LINQ to Entities - 无法投射' System.DateTime'输入' System.Object'按顺序

时间:2011-03-03 00:19:41

标签: entity-framework linq-to-entities

我正在尝试按照传递给表达式<中的日期来按顺序排序IQueryable实体。 FUNC< T,对象>>并且我得到错误:“无法将类型'System.Nullable`1'强制转换为'System.Object'.LINQ to Entities仅支持转换实体数据模型基元类型。”该实体上有一个可以为null的datetime属性,我试图对其进行排序:

示例:(其中e.Date是可以为空的DateTime)

Expression<Func<T,object>> sorter = (e) => e.Date;
IOrderedQueryable<T> sortedData = data.OrderBy(sorter);

提前致谢!

4 个答案:

答案 0 :(得分:5)

我写了一个简单的类,用于在运行时基于lambda表达式对实体进行排序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace DataModeling
{
    public class QueryOrderer<TEntity>
        where TEntity : class
    {
        private LambdaExpression defaultSortExpression;
        private Dictionary<string, LambdaExpression> orderFieldLookup;

        public QueryOrderer()
        {
            orderFieldLookup = new Dictionary<string, LambdaExpression>();
        }

        public void AddOrderMapping<TProp>(string fieldName, Expression<Func<TEntity, TProp>> selector)
        {
            orderFieldLookup[fieldName] = selector;
        }

        public void SetDefaultSortExpression<TProp>(Expression<Func<TEntity, TProp>> selector)
        {
            defaultSortExpression = selector;
        }

        public IQueryable<TEntity> GetOrderedEntries(string field, bool isDescending, IQueryable<TEntity> entries)
        {
            return orderEntries(entries, field, isDescending);
        }

        private IQueryable<TEntity> orderEntries(IQueryable<TEntity> entries, string fieldName, bool isDescending)
        {
            dynamic lambda = getOrderByLambda(entries, fieldName);
            if (lambda == null)
            {
                return entries;
            }
            if (isDescending)
            {
                return Queryable.OrderByDescending(entries, lambda);
            }
            else
            {
                return Queryable.OrderBy(entries, lambda);
            }
        }

        private dynamic getOrderByLambda(IQueryable<TEntity> entries, string fieldName)
        {
            if (!String.IsNullOrWhiteSpace(fieldName) && orderFieldLookup.ContainsKey(fieldName))
            {
                return orderFieldLookup[fieldName];
            }
            else
            {
                return defaultSortExpression;
            }
        }
    }
}

通过初始设置所有字段来使用此类:

QueryOrderer<User> orderer = new QueryOrderer<User>();
orderer.SetDefaultSortExpression(u => u.FullName);
orderer.AddOrderMapping("UserId", u => u.UserId);
orderer.AddOrderMapping("Name", u => u.FullName);
orderer.AddOrderMapping("Email", u => u.Email);
orderer.AddOrderMapping("CreatedOn", u => u.CreatedOn);

...

var users = orderer.GetOrderedEntries("CreatedOn", isDescending: false, context.Users);

这段代码的一个很好的功能是它可以完美地处理查找值。例如,如果您尝试使用描述而不是键进行排序,则可以在构建排序表达式时使用外部上下文:

orderer.AddOrderMapping("UserType", 
    u => context.UserTypes
                .Where(t => t.UserTypeId == u.UserTypeId)
                .Select(t => t.Description)
                .FirstOrDefault());

实体框架非常智能,只需将子查询折叠到外部查询中即可。

答案 1 :(得分:1)

此处有两个问题:首先您在分拣机中使用object,您应该使用DateTime。其次,每个元素必须在顺序中有一个位置,因此您必须定义Date为null的元素应该发生什么:

Expression<Func<T, DateTime>> sorter = (e) => e.Date ?? DateTime.MaxValue;
IOrderedQueryable<T> sortedData = data.OrderBy(sorter);

答案 2 :(得分:0)

尝试重建表达体

private LambdaExpression CreateLambdaPropertyGetter(Expression<Func<TEntity, object>> expression)
    {
        Expression body;
        if (expression.Body is UnaryExpression && ((UnaryExpression)expression.Body).NodeType == ExpressionType.Convert)            
            body = ((UnaryExpression)expression.Body).Operand;            
        else
            body = expression.Body;
        var lambda = Expression.Lambda(body, expression.Parameters);

        return lambda;
    }

答案 3 :(得分:0)

尝试在Func上使用Expression<Func>委托

Func<T,object> sorter = (e) => e.Date;
IOrderedEnumerable<T> sortedData = data.OrderBy(sorter);