anıl yıldırım
anıl yıldırım

Reputation: 963

Linq dynamic Sum

I want to send a sum after I have collected multiple fields in the database. But I need to write the fields as string. I may not be able to fully explain my problem, I will try to exemplify it.

What I want to do is this code's lambda state

I want to do :

expression = x => x.M1_TotalLoss + x.M2_TotalLoss;

My Code :

var param = Expression.Parameter(typeof(FooDomain), "x");
var value = Expression.Property(param, ("M1_TotalLoss"+"M2_TotalLoss"));

var rest = Expression.Lambda<Func<FooDomain, double>>(value, param);

var result = myContext.FooDomain().
                GroupBy(gp=>gp.Year).
                Select(s => new
                {
                    TotalLoss = Math.Round(s.AsQueryable().Sum(rest), 2)
                }).
                OrderByDescending(o => o.TotalLoss).
                ToList();

But since I can not write the predicate correctly, I get the following error:

exceptionMessage= Example feature 'M1_TotalLossM2_TotalLoss' not defined for type 'FooDomain'.

Upvotes: 1

Views: 207

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205629

Let see what we have here:

x => x.M1_TotalLoss + x.M2_TotalLoss

x apparently is a parameter, so

var param = Expression.Parameter(typeof(FooDomain), "x");

is ok.

x.M1_TotalLoss and x.M2_TotalLoss are properties of the parameter x called respectively "M1_TotalLoss" and "M2_TotalLoss", so let reflect that:

var value1 = Expression.Property(param, "M1_TotalLoss");
var value2 = Expression.Property(param, "M2_TotalLoss");

and x.M1_TotalLoss + x.M2_TotalLoss is just the add operation of the two:

var value = Expression.Add(value1, value2);

and you are done - the rest of the code is ok.

What about more than 2 properties?

Since op1 + op2 + op3 is equivalent of (op1 + op2) + op3, or with method notation Add(Add(op1, op2), op3), it can be seen that N additions can be described recursively as adding the next operand to the result of the addition of the previous operands. Which can easily be implemented with LINQ Aggregate method.

So given IEnumerable<string> containing the desired property names, you can use something like this:

var propertyNames = new [] { "M1_TotalLoss", "M2_TotalLoss", };

var param = Expression.Parameter(typeof(FooDomain), "x");
var value = propertyNames.Select(name => Expression.Property(param, name))
    .Aggregate<Expression>(Expression.Add);

// the rest of the code (same as yours)

Upvotes: 2

Related Questions