I am tryi开发者_高级运维ng to order an IQueryable of entities by date from a passed in Expression< Func< T, object>> and am getting the error: "Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types." The entity has a nullable datetime property on it on which I am trying to sort:
Example: (where e.Date is a nullable DateTime)
Expression<Func<T,object>> sorter = (e) => e.Date;
IOrderedQueryable<T> sortedData = data.OrderBy(sorter);
Thanks in advance!
I wrote a simple class for ordering entities based on a lambda expression at runtime.
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;
            }
        }
    }
}
You use this class by initially setting up all of the fields:
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);
I nice feature of this code is that it handles look-up values perfectly. For instance, if you're trying to sort using the description rather than a key, you can use the outer context when building up the sort expression:
orderer.AddOrderMapping("UserType", 
    u => context.UserTypes
                .Where(t => t.UserTypeId == u.UserTypeId)
                .Select(t => t.Description)
                .FirstOrDefault());
Entity Framework is smart enough to just fold the sub-query right into the outer query.
Two problem here: First you use object in your sorter, you should use DateTime. Secondly every element must have a place in the order so you have to define what should happen with elements where Date is null:
Expression<Func<T, DateTime>> sorter = (e) => e.Date ?? DateTime.MaxValue;
IOrderedQueryable<T> sortedData = data.OrderBy(sorter);
Try to reconstruct expression body
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;
    }
Try using Func delegate instead on Expression<Func>
Func<T,object> sorter = (e) => e.Date;
IOrderedEnumerable<T> sortedData = data.OrderBy(sorter);
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
 加载中,请稍侯......
      
精彩评论