Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda Expression to be used in Select() query

I am trying to build a lambda expression, containing two assignments (as shown further down), that I can then pass to a Queryable.Select() method.

I am trying to pass a string variable into a method and then use that variable to build up the lambda expression so that I can use it in a LINQ Select query.

My reasoning behind it is that I have a SQL Server datasource with many column names, I am creating a charting application that will allow the user to select, say by typing in the column name, the actual column of data they want to view in the y-axis of my chart, with the x-axis always being the DateTime. Therefore, they can essentially choose what data they chart against the DateTime value (it’s a data warehouse type app).

I have, for example, a class to store the retrieved data in, and hence use as the chart source of:

public class AnalysisChartSource
{
    public DateTime Invoicedate { get; set; }
    public Decimal yValue { get; set; }
}

I have (purely experimentaly) built an expression tree for the Where clause using the String value and that works fine:

public void GetData(String yAxis)
{
    using (DataClasses1DataContext db = new DataClasses1DataContext())
    {
        var data = this.FunctionOne().AsQueryable<AnalysisChartSource>();
        //just to get some temp data in....

        ParameterExpression pe = Expression.Parameter(typeof(AnalysisChartSource), "p");
        Expression left = Expression.MakeMemberAccess(pe,
                                                typeof(AnalysisChartSource).GetProperty(yAxis));
        Expression right = Expression.Constant((Decimal)16);
        Expression e2 = Expression.LessThan(left, right);
        Expression expNew = Expression.New(typeof(AnalysisChartSource));

        LambdaExpression le = Expression.Lambda(left, pe);

        MethodCallExpression whereCall = Expression.Call(
            typeof(Queryable), "Where", new Type[] { data.ElementType },
            data.Expression,
            Expression.Lambda<Func<AnalysisChartSource, bool>>(e2, new ParameterExpression[] { pe }));
    }
}

However……I have tried a similar approach for the Select statement, but just can’t get it to work as I need the Select() to populate both X and Y values of the AnalysisChartSource class, like this:

.Select(c => new AnalysisChartSource 
{ Invoicedate = c.Invoicedate, yValue = c.yValue}).AsEnumerable();

How on earth can I build such an expression tree….or….possibly more to the point…..is there an easier way that I have missed entirely?

like image 239
jameschinnock Avatar asked Apr 27 '10 08:04

jameschinnock


People also ask

How do you write a select query in lambda expression?

select (s => new SelectListItem { Value = s. ID. ToString(), Text = s.Name} ); select (s => new SelectListItem { Value = s.ID + "", Text = s.Name} );

How do you select lambda?

When choosing a lambda value, the goal is to strike the right balance between simplicity and training-data fit: If your lambda value is too high, your model will be simple, but you run the risk of underfitting your data. Your model won't learn enough about the training data to make useful predictions.

Can you use lambda expression instead of LINQ query?

So performance-wise, there's no difference whatsoever between the two. Which one you should use is mostly personal preference, many people prefer lambda expressions because they're shorter and more concise, but personally I prefer the query syntax having worked extensively with SQL.

What does => mean in LINQ?

The => operator can be used in two ways in C#: As the lambda operator in a lambda expression, it separates the input variables from the lambda body. In an expression body definition, it separates a member name from the member implementation.


1 Answers

I find that the best way to work out how to build expression trees is to see what the C# compiler does. So here's a complete program:

using System;
using System.Linq.Expressions;

public class Foo
{
    public int X { get; set; }
    public int Y { get; set; }
}

class Test
{
    static void Main()
    {
        Expression<Func<int, Foo>> builder = 
            z => new Foo { X = z, Y = z };
    }
}

Compile that, open the results in Reflector and set the optimisation to .NET 2.0. You end up with this generated code for the Main method:

ParameterExpression expression2;
Expression<Func<int, Foo>> expression = 
  Expression.Lambda<Func<int, Foo>>(
    Expression.MemberInit(
      Expression.New((ConstructorInfo) methodof(Foo..ctor), new Expression[0]),
      new MemberBinding[] { Expression.Bind((MethodInfo) methodof(Foo.set_X),
                           expression2 = Expression.Parameter(typeof(int), "z")),
                           Expression.Bind((MethodInfo) methodof(Foo.set_Y), 
                                            expression2) }
    ),
    new ParameterExpression[] { expression2 });

Basically, I think Expression.MemberInit is what you're after.

like image 92
Jon Skeet Avatar answered Sep 27 '22 22:09

Jon Skeet