Pregunta

He usado expresiones C # anteriormente basadas en lamdas, pero no tengo experiencia componiéndolas a mano. Dada una Expression < Func < SomeType, bool > > originalPredicate , quiero crear una Expression < Func < OtherType, bool > > translatePredicate .

En este caso SomeType y OtherType tienen los mismos campos, pero no están relacionados (sin herencia y no se basan en una interfaz común).

Antecedentes: tengo una implementación de repositorio basada en LINQ to SQL. Proyecto las entidades LINQ to SQL en mis entidades Model, para mantener mi modelo en POCO. Quiero pasar expresiones al repositorio (como una forma de especificaciones) pero deberían basarse en las entidades modelo. Pero no puedo pasar esas expresiones al contexto de datos, ya que espera expresiones basadas en las entidades LINQ to SQL.

¿Fue útil?

Solución

Con Expression , la forma más simple es con una conversión expresión :

class Foo {
    public int Value { get; set; }
}
class Bar {
    public int Value { get; set; }
}
static class Program {
    static void Main() {
        Expression<Func<Foo, bool>> predicate =
            x => x.Value % 2 == 0;
        Expression<Func<Bar, Foo>> convert =
            bar => new Foo { Value = bar.Value };

        var param = Expression.Parameter(typeof(Bar), "bar");
        var body = Expression.Invoke(predicate,
              Expression.Invoke(convert, param));
        var lambda = Expression.Lambda<Func<Bar, bool>>(body, param);

        // test with LINQ-to-Objects for simplicity
        var func = lambda.Compile();
        bool withOdd = func(new Bar { Value = 7 }),
             withEven = func(new Bar { Value = 12 });
    }
}

Sin embargo, tenga en cuenta que esto será apoyado de manera diferente por diferentes proveedores. Puede que a EF no le guste, por ejemplo, incluso si LINQ-to-SQL sí.

La otra opción es reconstruir el árbol de expresión completamente , usando la reflexión para encontrar los miembros correspondientes. Mucho más complejo.

Otros consejos

Hay otra forma que he encontrado, que también incluye envolver su delegado original.

Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression)
{
    Expression<Func<T, object>> g = obj => expression.Compile().Invoke(obj);
    return g.Compile();
}

No hay una forma implícita de hacer la traducción. Debe envolver su delegado existente dentro de una lambda que crea un nuevo tipo a partir del tipo de argumento:

var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x))

Donde OtherTypeFromSomeType crea la instancia OtherType a partir del argumento SomeType .

Tuve el mismo problema que tú y lo solucioné así con EF:

var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>>

Entity Framework sabe cómo construir el comando sql correcto. La conversión de la expresión es mucho más complicada, porque está diseñada para ser inmutable y podría causar efectos de tiempo de ejecución no deseados si hace algo mal y, al menos en mi caso, no es necesaria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top