How to merge object expressions?

2019-07-25 09:24发布

My question is How can I merge object expressions like this one?

Func<T, object>

I created a test project on GitHub where I show what I have been trying.

I have a basic boolian expression combination like this here working

Expression<Func<Employee, bool>> filter1 = p => p.Name == "John Doe";
Expression<Func<Employee, bool>> filter2 = p => p.Address == "Address 123";

// Two boolean expressions combined
Expression<Func<Employee, bool>> filterCombined = filter1.And(filter2);

// Works as expected
filterCombined.Body.ToString().ShouldBe("((p.Name == \"John Doe\") And (p.Address == \"Address 123\"))");

BUT what I can't get working is to combine two object ones like here

Expression<Func<Employee, object>> filter1 = p => p.Info;
Expression<Func<Employee, object>> filter2 = p => p.Profile;

// Trying to combine two object expressions fails
Expression<Func<Employee, object>> filterCombined = ParameterToMemberExpressionRebinder.CombinePropertySelectorWithPredicate(filter1, filter2);

filterCombined.Body.ToString().ShouldBe("((p => p.Info And p => p.Profile))"); //Something like this anyway...

I have tried all kinds of things like vistor pattern, LinqKit etc. but I´m missing something.

My main reason for doing this all

This information isn't strictly needed for this question but might give some somebody some extra insight and me some different answers.

I need this for Entity Framework Include to load related data. But above that Automapper can't map the following so I'm trying to take all the params and combine them into one that Automapper can then handle.

public MyModelDTO GetById(int? id, params Expression<Func<MyModelDTO , object>>[] includeExpressions)
{
  // here Automapper (with Automapper.Extension.ExpressionMapping) 
  // fails to do the mapping so I´m trying to combine them into one
  Expression<Func<MyModel, object>> mappedExpression= MapToType<Expression<Func<MyModel, object>>>(includeExpressions);

   // call the repository with EF expression
   var myModel = MyRepoGetById(id,mappedExpression);
   ...map myModel back to dto
   return myMappedDtoModel;
}

// The repository method
public MyModel  MyRepoGetById(int id, params Expression<Func<MyModel, object>>[] includeExpressions)
{
        if (includeExpressions.Any())
        {
            IQueryable<T> set = includeExpressions
              .Aggregate<Expression<Func<T, object>>, IQueryable<T>>
                (dbContext.Set<T>(), (current, expression) => current.Include(expression));

            return await set.SingleOrDefaultAsync(s => s.Id == id);
        }

        return dbContext.Set<T>().Find(id);
}

that I want to use like this

var result  = await service.GetById(id,x => x.ClassProperty, x => x.AnotherClassProperty);

标签: c# linq lambda
0条回答
登录 后发表回答