1

I'm trying to implement dynamic projection for Entity Framework to be able to specify list of properties to return ang get a dictionary of values as a result.

        public static IQueryable<Dictionary<string, object>> ProjectionMap<TSource>
        (IQueryable<TSource> sourceModel, IEnumerable<string> properties) 
    {
        var itemParam = Expression.Parameter(typeof (TSource), "item");

        var addMethod = typeof (Dictionary<string, object>).GetMethod("Add");

        var elements = properties.
            Select(
                property =>
                Expression.ElementInit(addMethod, Expression.Constant(property),
                                       GetPropertyExpression<TSource>(itemParam, property))).
            ToList();

        var newDictionaryExpression =
            Expression.New(typeof (Dictionary<string, object>));

        var dictionaryInit = Expression.ListInit(newDictionaryExpression, elements);

        var projection = Expression.Lambda<Func<TSource, Dictionary<string, object>>>(dictionaryInit, itemParam);

        return sourceModel.Select(projection);
    }

    public static Expression GetPropertyExpression<T>(ParameterExpression parameter, string propertyName) 
    {
        var properties = typeof (T).GetProperties();
        var property = properties.First(p => p.Name == propertyName);
        return Expression.Property(parameter, property);
    }

At runtime running the following code raise exception

var query = ProjectionMap(db.Posts, new[]{"Subject"});
            var result = query.ToList();

NotSupportedException Only list initializer items with a single element are supported in LINQ to Entities.

Any ideas how to fix the code or suggestion how to implement it properly ? Thanks in advance.

1 Answers1

0

I got the same error, but maybe for a different reason (I haven't tried your code). Hoping this helps someone I just added a .ToList() before the select. I was selecting into a Hashtable, and I assume the problem was that sql didn't know how to do that, although I'm used to seeing a different error. Anyway, maybe try

    return sourceModel.ToList().Select(projection);

as sourceModel is your IQueryable (at first I was going to suggest ToList() on properties, but that is already IEnumerable.

Gary
  • 3,254
  • 2
  • 27
  • 30