Question

J'ai déjà utilisé des expressions C # basées sur des lamdas, mais je n’ai aucune expérience de leur composition manuelle. Avec un Expression < Func < SomeType, bool > > originalPredicate , je souhaite créer un Expression < Func & OtherType, bool > > translationsPredicate .

Dans ce cas, SomeType et OtherType ont les mêmes champs, mais ils ne sont pas liés (pas d'héritage et pas basés sur une interface commune).

Background: J'ai une implémentation de référentiel basée sur LINQ to SQL. Je projette les entités LINQ to SQL sur mes entités Model afin de conserver mon modèle dans POCO. Je souhaite transmettre des expressions au référentiel (sous forme de spécifications), mais elles doivent être basées sur les entités du modèle. Mais je ne peux pas transmettre ces expressions au contexte de données, car il attend des expressions basées sur les entités LINQ to SQL.

Était-ce utile?

La solution

Avec Expression , la méthode la plus simple consiste à utiliser une expression de conversion:

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

Notez cependant que cela sera pris en charge différemment par différents fournisseurs. EF peut ne pas l’aimer, par exemple, même si LINQ-to-SQL l’aime.

L’autre option consiste à reconstruire l’arbre d’expression complètement , en utilisant la réflexion pour rechercher les membres correspondants. Beaucoup plus complexe.

Autres conseils

Il existe un autre moyen que j'ai trouvé, qui consiste également à emballer votre délégué d'origine.

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

Il n'y a pas de moyen implicite de faire la traduction. Vous devez envelopper votre délégué existant dans un lambda qui crée un nouveau type à partir du type d'argument:

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

OtherTypeFromSomeType crée l'instance OtherType à partir de l'argument SomeType .

J'ai eu le même problème que vous et je l'ai corrigé comme ça avec EF:

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

Entity Framework sait comment construire la commande SQL correcte. La conversion de l'expression est beaucoup plus compliquée, car elle est conçue pour être immuable et peut avoir des effets non souhaités sur l'exécution si vous faites quelque chose de mal et, dans mon cas du moins, cela n'est pas nécessaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top