2017-05-06 1 views
4

Si je veux récupérer plus de colonnes avec une expression d'arbre lambda déjà existante comme ci-dessous, comment ferais-je cela? Cela fonctionne avec Entity Frameworks et que vous voulez qu'il fonctionne encore.Ajouter à Lambda Expression et travailler avec Entity Framework

Expression<Func<DivisionTeam, DirectorTeamModel>> columns= (d) => new DirectorTeamModel 
{ 
    Id = d.Id, 
    TeamId = d.Team.Id 
}; 

if (criteria.Template == ExportTemplate.Import || criteria.Template == ExportTemplate.Default) 
{ 
    // Retrieve additional columns from "columns" expression tree 
} 

return _divisionTeamsRepository.GetPagedResults(criteria.Page, criteria.PageSize, @where.Expand(), string.Format("{0} {1}", criteria.SortOrder, criteria.SortDirection), columns); 
+0

http://stackoverflow.com/questions/16516971/linq-dynamic-select –

+3

Qu'est-ce qui ne va pas avec 'columns = d => {var c = columns(); c.OtherProperty = d.OtherProperty; retour c; } '? S'il vous plaît être plus précis sur ce que vous avez essayé, et ce que vous avez des problèmes spécifiques. Votre question est très large en ce moment. –

+0

Vous ne pensez pas que je l'ai déjà fait? On dirait que vous n'avez pas testé cela parce que vous obtenez cette erreur. 'Une expression lambda avec un corps d'instruction ne peut pas être convertie en un arbre d'expression –

Répondre

2

Étant donné deux expressions « sélecteur », vous avez à prendre les fixations de leur MemberInitExpression et de créer une nouvelle expression en utilisant toutes les liaisons. Mais cette expression ne va pas fonctionner, car elle utilise deux expressions de paramètres différentes pour un seul paramètre. Nous devons régler cela aussi.

... Compte tenu

Expression<Func<TSource, TResult>> left = ... // columns 
Expression<Func<TSource, TResult>> right = ... // more columns 

... prendre les fixations ...

var leftInit = left.Body as MemberInitExpression; 
var rightInit = right.Body as MemberInitExpression; 

var bindings = leftInit.Bindings.Concat(rightInit.Bindings); 

... créer une nouvelle expression ...

var result = Expression.Lambda<Func<TSource, TResult>>(
    Expression.MemberInit(Expression.New(typeof(TResult)), bindings), ???); 

.. .BUT, besoin de paramètre unique ...

var binder = new ParameterBinder(left.Parameters[0], right.Parameters[0]); 
var bindings = binder.Visit(leftInit.Bindings.Concat(rightInit.Bindings)); 

// now, just use right.Parameters[0] as parameter... 

Et, en remplaçant les paramètres fonctionne bien en utilisant un visiteur d'expression:

class ParameterBinder : ExpressionVisitor 
{ 
    readonly ParameterExpression parameter; 
    readonly Expression replacement; 

    public ParameterBinder(ParameterExpression parameter, Expression replacement) 
    { 
     this.parameter = parameter; 
     this.replacement = replacement; 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     if (node == parameter) 
      return replacement; 

     return base.VisitParameter(node); 
    } 
} 

Abstracting ce genre de choses plomberie fonctionne très bien. En fait, vous pouvez simplement utiliser un existing library (spoiler: Je suis l'auteur), ce qui devrait conduire à quelque chose comme ça:

var merged = columns.Apply(moreColumns); 
+0

@Mike cela aide-t-il? (Votre prime se termine dans les 2 jours ...) –