Entity framework 实体框架:LINQ to Entities仅支持转换实体数据模型基元类型

Entity framework 实体框架:LINQ to Entities仅支持转换实体数据模型基元类型,entity-framework,primitive-types,Entity Framework,Primitive Types,我编写了一个方法,允许为orderby子句传入表达式,但遇到了这个问题 无法强制转换该类型 要键入的“System.DateTime” “System.IComparable”。LINQ到实体 仅支持转换实体数据 模型基元类型 基本上是这样表达的: Expression<Func<K, IComparable>> orderBy 这样我就可以使用字典来保存表达式的字符串匹配,如: _possibleSortForForumItem.Add("CreateDate", i

我编写了一个方法,允许为orderby子句传入表达式,但遇到了这个问题

无法强制转换该类型 要键入的“System.DateTime” “System.IComparable”。LINQ到实体 仅支持转换实体数据 模型基元类型

基本上是这样表达的:

Expression<Func<K, IComparable>> orderBy
这样我就可以使用字典来保存表达式的字符串匹配,如:

_possibleSortForForumItem.Add("CreateDate", item => item.CreateDate);
然后我有一个方法,它接受排序字符串,如果它与字典中的键匹配,则返回表达式,如果不匹配,则返回一些默认值。(这个想法是一种控制它可以被排序的方式)现在这适用于字符串属性,但到目前为止还不适用于datetime或integer,因为我得到了上面的错误消息

现在,据我(粗略地)理解,问题在于实体框架需要它是主/EDM类型,因为它必须将C#DateTime转换为数据库可以处理的内容

有没有办法将datetime转换为基元类型,这样它仍然可以工作

解决方案

通过方法获取订单的方法:(接受查询并以“ordered form”形式返回)


实体框架使这一点变得困难,我不确定是否有一种方法可以处理单个返回值类型(IComparable、object等)。您可能会考虑将您的设计改写成名称为-<代码> FUNC值的字典:

_possibleSortForForumItem.Add("CreateDate", 
    query => query.OrderBy(item.CreateDate));
然后像这样应用它:

var orderedQuery = query.OrderBy(item => item.DefaultOrderColumn);

Func<IQueryable<K>, IOrderedQueryable<K>> assignOrderBy = null;

if (_possibleSortForForumItem.TryGetValue(orderColumnName, out assignOrderBy))
{
    orderedQuery = assignOrderBy(query);
}
var orderedQuery=query.OrderBy(item=>item.DefaultOrderColumn);
Func assignOrderBy=null;
if(_possibleSortforumItem.TryGetValue(orderColumnName,out assignOrderBy))
{
orderedQuery=assignOrderBy(查询);
}

我知道这很旧,但我想完成与OP完全相同的任务,不想使用字典中的
函数。主要是因为我必须实现
OrderBy
OrderByDescending
委托

我最终为IQueryable创建了一个名为
ObjectSort
的扩展方法,该方法只需检查表达式的返回类型,然后使用该类型创建一个新的lambda,这样LINQ to Entities就不会崩溃

我不确定这是否是一个好的解决方案,但下面的示例确实适用于
DateTime
int
,因此如果您希望完成类似的任务,希望它能给您一些想法

public static IOrderedQueryable<T> ObjectSort<T>(this IQueryable<T> entities, Expression<Func<T, object>> expression, SortOrder order = SortOrder.Ascending)
{
    var unaryExpression = expression.Body as UnaryExpression;
    if (unaryExpression != null)
    {
        var propertyExpression = (MemberExpression)unaryExpression.Operand;
        var parameters = expression.Parameters;

        if (propertyExpression.Type == typeof(DateTime))
        {
            var newExpression = Expression.Lambda<Func<T, DateTime>>(propertyExpression, parameters);
            return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
        }

        if (propertyExpression.Type == typeof(int))
        {
            var newExpression = Expression.Lambda<Func<T, int>>(propertyExpression, parameters);
            return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
        }

        throw new NotSupportedException("Object type resolution not implemented for this type");
    }
    return entities.OrderBy(expression);
}
public static IOrderedQueryable ObjectSort(此IQueryable实体、表达式、SortOrder order=SortOrder.升序)
{
var unaryExpression=expression.Body作为unaryExpression;
if(一元表达式!=null)
{
var propertyExpression=(MemberExpression)unaryExpression.Operator;
var参数=表达式参数;
if(propertyExpression.Type==typeof(DateTime))
{
var newExpression=Expression.Lambda(propertyExpression,参数);
返回顺序==SortOrder.Ascending?entities.OrderBy(newExpression):entities.OrderByDescending(newExpression);
}
if(propertyExpression.Type==typeof(int))
{
var newExpression=Expression.Lambda(propertyExpression,参数);
返回顺序==SortOrder.Ascending?entities.OrderBy(newExpression):entities.OrderByDescending(newExpression);
}
抛出新的NotSupportedException(“此类型未实现对象类型解析”);
}
返回实体.OrderBy(表达式);
}

遇到了与原始海报类似的问题,其中“Order By”表达式被写成表达式类型的lambdas。NHibernate linq提供程序正确解释了这些类型,但迁移到EF 5导致“无法将类型“System.DateTime”转换为类型“System.IComparable”。linq to Entities仅支持转换实体数据模型基元类型。”

以下方法在调用各种“OrderBy”方法(使用反射-道歉…)时提供了到表达式的转换。请注意,它们最初封装在一个泛型类OrderBy中

private static readonly Type QueryableType=typeof(Queryable);
//HACK:使用反射来调用强类型方法,而不是基于对象的方法
//这是为了解决“无法将类型'System.DateTime'强制转换为类型'System.Object'。LINQ to Entities仅支持强制转换实体数据模型基元类型。”
私有IOrderedQueryable应用程序代理(
可查询的查询,
表达式键选择器,
布尔分类,
bool用户选择)
{
if(useReflection)
{
var body=keySelector.body作为一元表达式;
var keyExpr=body.Operand作为MemberExpression;
返回(IOrderedQueryable)query.Provider.CreateQuery(
表情,打电话(
QueryableType,
排序规则?“OrderBy”:“OrderByDescending”,
新类型[]{typeof(T),keyExpr.Type},
query.Expression,
表达式Lambda(keyExpr,keySelector.Parameters));
}
其他的
{
如果(排序)
返回query.OrderBy(keySelector);
其他的
返回query.OrderByDescending(keySelector);
}
}
//HACK:使用反射来调用强类型方法,而不是基于对象的方法
//这是为了解决“无法将类型'System.DateTime'强制转换为类型'System.Object'。LINQ to Entities仅支持强制转换实体数据模型基元类型。”
私有IOrderedQueryable应用程序代理(
IOrderedQueryable查询,
表达式键选择器,
布尔分类,
bool用户选择)
{
if(useReflection)
{
var body=keySelector.body作为一元表达式;
瓦克
initialQuery = query
  .Where
  (
    somethingEqualsSomething
  )
  .Select
  (
    selectClause
  );

var orderedQuery = orderBy(initialQuery);

returnValue = orderedQuery
  .Skip(numberToShow * realPage)
  .Take(numberToShow)
  .ToList();
_possibleSortForForumItem.Add("CreateDate", 
    query => query.OrderBy(item.CreateDate));
var orderedQuery = query.OrderBy(item => item.DefaultOrderColumn);

Func<IQueryable<K>, IOrderedQueryable<K>> assignOrderBy = null;

if (_possibleSortForForumItem.TryGetValue(orderColumnName, out assignOrderBy))
{
    orderedQuery = assignOrderBy(query);
}
public static IOrderedQueryable<T> ObjectSort<T>(this IQueryable<T> entities, Expression<Func<T, object>> expression, SortOrder order = SortOrder.Ascending)
{
    var unaryExpression = expression.Body as UnaryExpression;
    if (unaryExpression != null)
    {
        var propertyExpression = (MemberExpression)unaryExpression.Operand;
        var parameters = expression.Parameters;

        if (propertyExpression.Type == typeof(DateTime))
        {
            var newExpression = Expression.Lambda<Func<T, DateTime>>(propertyExpression, parameters);
            return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
        }

        if (propertyExpression.Type == typeof(int))
        {
            var newExpression = Expression.Lambda<Func<T, int>>(propertyExpression, parameters);
            return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
        }

        throw new NotSupportedException("Object type resolution not implemented for this type");
    }
    return entities.OrderBy(expression);
}
    private static readonly Type QueryableType = typeof(Queryable);

    // HACK: Use reflection to call strongly-typed methods instead of object-based methods
    // This is to work around "Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types."
    private IOrderedQueryable<T> ApplyOrderByTo(
        IQueryable<T> query,
        Expression<Func<T, object>> keySelector,
        bool sortAscending,
        bool useReflection)
    {
        if (useReflection)
        {
            var body = keySelector.Body as UnaryExpression;
            var keyExpr = body.Operand as MemberExpression;

            return (IOrderedQueryable<T>)query.Provider.CreateQuery(
                Expression.Call(
                QueryableType,
                sortAscending ? "OrderBy" : "OrderByDescending",
                new Type[] { typeof(T), keyExpr.Type },
                query.Expression,
                Expression.Lambda(keyExpr, keySelector.Parameters)));
        }
        else
        {
            if (sortAscending)
                return query.OrderBy(keySelector);
            else
                return query.OrderByDescending(keySelector);
        }
    }

    // HACK: Use reflection to call strongly-typed methods instead of object-based methods
    // This is to work around "Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types."
    private IOrderedQueryable<T> ApplyOrderByTo(
        IOrderedQueryable<T> query,
        Expression<Func<T, object>> keySelector,
        bool sortAscending,
        bool useReflection)
    {
        if (useReflection)
        {
            var body = keySelector.Body as UnaryExpression;
            var keyExpr = body.Operand as MemberExpression;

            return (IOrderedQueryable<T>)query.Provider.CreateQuery(
                Expression.Call(
                QueryableType,
                sortAscending ? "ThenBy" : "ThenByDescending",
                new Type[] { typeof(T), keyExpr.Type },
                query.Expression,
                Expression.Lambda(keyExpr, keySelector.Parameters)));
        }
        else
        {
            if (sortAscending)
                return query.ThenBy(keySelector);
            else
                return query.ThenByDescending(keySelector);
        }
    }
        /// <summary>
    ///     Supports sorting of a given member as an expression when type is not known. It solves problem with LINQ to Entities unable to
    ///     cast different types as 'System.DateTime', 'System.DateTime?' to type 'System.Object'.
    ///     LINQ to Entities only supports casting Entity Data Model primitive types.
    /// </summary>
    /// <typeparam name="T">entity type</typeparam>
    /// <param name="query">query to apply sorting on.</param>
    /// <param name="expression">the member expression to apply</param>
    /// <param name="sortOrder">the sort order to apply</param>
    /// <returns>Query with sorting applied as IOrderedQueryable of type T</returns>
    public static IOrderedQueryable<T> OrderByMember<T>(
        this IQueryable<T> query, 
        Expression<Func<T, object>> expression, 
        SortOrder sortOrder)
    {
        var body = expression.Body as UnaryExpression;

        if (body != null)
        {
            var memberExpression = body.Operand as MemberExpression;

            if (memberExpression != null)
            {
                return
                    (IOrderedQueryable<T>)
                    query.Provider.CreateQuery(
                        Expression.Call(
                            typeof(Queryable), 
                            sortOrder == SortOrder.Ascending ? "OrderBy" : "OrderByDescending",
                            new[] { typeof(T), memberExpression.Type }, 
                            query.Expression,
                            Expression.Lambda(memberExpression, expression.Parameters)));
            }
        }

        return sortOrder == SortOrder.Ascending ? query.OrderBy(expression) : query.OrderByDescending(expression);
    }

    /// <summary>
    ///     Supports sorting of a given member as an expression when type is not known. It solves problem with LINQ to Entities unable to
    ///     cast different types as 'System.DateTime', 'System.DateTime?' to type 'System.Object'.
    ///     LINQ to Entities only supports casting Entity Data Model primitive types.
    /// </summary>
    /// <typeparam name="T">entity type</typeparam>
    /// <param name="query">query to apply sorting on.</param>
    /// <param name="expression">the member expression to apply</param>
    /// <param name="sortOrder">the sort order to apply</param>
    /// <returns>Query with sorting applied as IOrderedQueryable of type T</returns>
    public static IOrderedQueryable<T> ThenByMember<T>(
        this IQueryable<T> query, 
        Expression<Func<T, object>> expression, 
        SortOrder sortOrder)
    {
        return ((IOrderedQueryable<T>)query).ThenByMember(expression, sortOrder);
    }

    /// <summary>
    ///     Supports sorting of a given member as an expression when type is not known. It solves problem with LINQ to Entities unable to
    ///     cast different types as 'System.DateTime', 'System.DateTime?' to type 'System.Object'.
    ///     LINQ to Entities only supports casting Entity Data Model primitive types.
    /// </summary>
    /// <typeparam name="T">entity type</typeparam>
    /// <param name="query">query to apply sorting on.</param>
    /// <param name="expression">the member expression to apply</param>
    /// <param name="sortOrder">the sort order to apply</param>
    /// <returns>Query with sorting applied as IOrderedQueryable of type T</returns>
    public static IOrderedQueryable<T> ThenByMember<T>(
        this IOrderedQueryable<T> query, 
        Expression<Func<T, object>> expression, 
        SortOrder sortOrder)
    {
        var body = expression.Body as UnaryExpression;

        if (body != null)
        {
            var memberExpression = body.Operand as MemberExpression;

            if (memberExpression != null)
            {
                return
                    (IOrderedQueryable<T>)
                    query.Provider.CreateQuery(
                        Expression.Call(
                            typeof(Queryable), 
                            sortOrder == SortOrder.Ascending ? "ThenBy" : "ThenByDescending",
                            new[] { typeof(T), memberExpression.Type }, 
                            query.Expression,
                            Expression.Lambda(memberExpression, expression.Parameters)));
            }
        }

        return sortOrder == SortOrder.Ascending ? query.ThenBy(expression) : query.ThenByDescending(expression);
    }
Expression<Func<TObject, DateTime>> Expr = obj=>obj.StartDate;
dynamic dynExpr=Expr;
query=query.OrderBy(dynExpr);
query=Queryable.OrderBy(query, dynExpr);