Generar expresiones lambda selectas dinámicas

entity-framework expression-trees lambda linq-to-entities

Pregunta

Soy algo nuevo en los árboles de expresión y simplemente no entiendo algunas cosas.

Lo que necesito hacer es enviar una lista de valores y seleccionar las columnas para una entidad de esos valores. Así que haría una llamada algo como esto:

DATASTORE<Contact> dst = new DATASTORE<Contact>();//DATASTORE is implemented below.
List<string> lColumns = new List<string>() { "ID", "NAME" };//List of columns
dst.SelectColumns(lColumns);//Selection Command

Quiero que se traduzca en un código como este (el Contact es una entidad que utiliza el EF4):

Contact.Select(i => new Contact { ID = i.ID, NAME = i.NAME });

Así que digamos que tengo el siguiente código:

public Class<t> DATASTORE where t : EntityObject
{
    public Expression<Func<t, t>> SelectColumns(List<string> columns)
    {
        ParameterExpression i = Expression.Parameter(typeof(t), "i");
        List<MemberBinding> bindings = new List<MemberBinding>();

        foreach (PropertyInfo propinfo in typeof(t).GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (columns.Contains(propinfo.Name))
            {
                MemberBinding binding = Expression.Bind(propinfo, Expression.Property(i, propinfo.Name));
                bindings.Add(binding);
            }
        }

        Expression expMemberInit = Expression.MemberInit(Expression.New(typeof(t)), bindings);
        return Expression.Lambda<Func<t, t>>(expMemberInit, i);
    }

Cuando ejecuté el código anterior obtuve el siguiente error:

La entidad o tipo complejo 'Contacto' no se puede construir en una consulta de LINQ to Entities.

Miré el cuerpo de la consulta y emití el siguiente código:

{i => new Contact() {ID = i.ID, NAME = i.NAME}}

Estoy bastante seguro de que debería poder construir una nueva entidad porque escribí esta línea explícitamente como una prueba para ver si esto se podría hacer:

.Select(i => new Contact{ ID = i.ID, NAME = i.NAME })

Esto funcionó, pero necesito construir el select dinámicamente.

Intenté descompilar una consulta directa (la primera vez que miré el código de bajo nivel) y no puedo traducirlo. El código de alto nivel que ingresé es:

Expression<Func<Contact, Contact>> expression = z => 
                    new Contact { ID = z.ID, NAME = z.NAME };

Cambiando el framework usado en el descompilador obtengo este código:

ParameterExpression expression2;
Expression<Func<Contact, Contact>> expression = 
   Expression.Lambda<Func<Contact, Contact>>
      (Expression.MemberInit(Expression.New((ConstructorInfo) methodof(Contact..ctor),
         new Expression[0]), new MemberBinding[] { Expression.Bind((MethodInfo) 
            methodof(Contact.set_ID), Expression.Property(expression2 = Expression.Parameter(typeof(Contact), "z"), (MethodInfo) 
            methodof(Contact.get_ID))), Expression.Bind((MethodInfo) 
            methodof(Contact.set_NAME), Expression.Property(expression2, (MethodInfo) 
               methodof(Contact.get_NAME))) }), new ParameterExpression[] { expression2 
        });

He buscado varios lugares para intentar entender esto, pero todavía no lo he conseguido. ¿Alguien puede ayudar?

Estos son algunos de los lugares que he visto:

Respuesta popular

Cuando lo hice la última vez, proyecté el resultado a una clase no asignada (no a una entidad) y funcionó, todo lo demás era igual que en tu código. ¿Está seguro de que no funciona la consulta dinámica como .Select (i => nuevo contacto {ID = i.ID, NAME = i.NAME})?



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow