Pergunta

Eu usei # expressões C antes baseado em lamdas, mas eu não tenho experiência compondo-los à mão. Dado um Expression<Func<SomeType, bool>> originalPredicate, eu quero criar um Expression<Func<OtherType, bool>> translatedPredicate.

Neste caso SomeType e OtherType têm os mesmos campos, mas eles não estão relacionados (sem herança e não com base em uma interface comum).

Fundo: Eu tenho uma implementação repositório baseado em LINQ to SQL. I projetar o LINQ to Entities SQL para meus entidades modelo, para manter o meu modelo em POCO. Eu quero passar expressões para o repositório (como uma forma de especificações), mas eles devem basear-se nas entidades do modelo. Mas não posso passar essas expressões para o contexto de dados, uma vez que espera expressões baseado no LINQ to Entities SQL.

Foi útil?

Solução

Com Expression, a maneira mais simples é com uma conversão expressão :

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 });
    }
}

Note, porém, que esta será apoiado de forma diferente por diferentes fornecedores. EF pode não gostar dele, por exemplo, mesmo que LINQ to SQL faz.

A outra opção é para reconstruir a árvore de expressão completamente , usando a reflexão para encontrar os membros correspondentes. Muito mais complexa.

Outras dicas

Há uma outra maneira que eu encontrei, que também inclui envolvendo o delegado originais.

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

Não há nenhuma maneira implícita para fazer a tradução. Você tem que envolver seu delegado existente dentro de um lambda que cria um novo tipo do tipo de argumento:

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

Onde OtherTypeFromSomeType cria a instância OtherType a partir do argumento SomeType.

Eu tive o mesmo problema que você e eu fixa-lo como esta com a EF:

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

Entity Framework sabe como construir o comando correto sql. Convertendo a expressão é muito mais complicado, porque ele é construído para ser imutável e pode causar efeitos indesejados tempo de execução se você fizer algo errado, e, no meu caso, pelo menos, ele não é necessário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top