Thursday, February 11, 2010

Now Change the LINQ Statement to Dynamic Lambda

But what if you don’t actually know at design time which properties need to be copied over or what the where clause should look like? In this case, you need to dynamically build a Lambda Expression to replace the LINQ statement.
  • You will need to use the Parameter factory method from System.Linq.Expressions.Expression to create two System.Linq.Expressions.ParameterExpression variables – one for Person and one for FileFormat.
  • You will need to use the New factory method from System.Linq.Expressions.Expression to create a System.Linq.Expressions.NewExpression variable for FileFormat with a value of “new FileFormat()”.
  • Create a generic list of System.Linq.Expressions.MemberBinding to hold all of the property bindings that will be used. This is the “PersonID = p.PersonID” portion of the statement. I recommend putting this into a separate method.
    • Use the GetMember method to create a System.Reflection.MemberInfo variable for the Property.
    • Use the PropertyOrField method of System.Linq.Expressions.LambdaExpression to create a MemberExpression variable.
    • Use the Bind method of System.Linq.Expressions.Expression to return the MemberBinding.
  • Use the MemberInit method of System.Linq.Expressions.Expression to create a MemberInitExpression variable.
  • Use the Lambda method of System.Linq.Expressions.BinaryExpression to create the Lambda expression for the select.
LISTING 1.3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
 
namespace DynamicLINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            IQueryable<Person> persons = new List<Person>{
                new Person{PersonID=1, CompanyID=1, FirstName="John", LastName="Smith"},
                new Person{PersonID=2, CompanyID=1, FirstName="Sam", LastName="Jones"},
                new Person{PersonID=3, CompanyID=1, FirstName="Jean", LastName="Smith"},
                new Person{PersonID=4, CompanyID=2, FirstName="Samantha", LastName="Maples"},
                new Person{PersonID=5, CompanyID=1, FirstName="Tom", LastName="Brown"}
            }.AsQueryable();
 
            ParameterExpression ffParam = Expression.Parameter(typeof(FileFormat), "f");
            ParameterExpression pParam = Expression.Parameter(typeof(Person), "p");
 
            Expression right = Expression.Constant(1);
            MemberExpression left = LambdaExpression.PropertyOrField(pParam, "CompanyID");
            BinaryExpression compareString = Expression.Equal(left, right);
            Expression<Func<Person, bool>> whereExp = (Expression<Func<Person, bool>>)
              BinaryExpression.Lambda(compareString, new ParameterExpression[] { pParam });
 
            NewExpression newExp = Expression.New(typeof(FileFormat));
 
            List<MemberBinding> bindings = new List<MemberBinding>();
            bindings.Add(GetMemberBinding("PersonID", pParam, "PersonID"));
            bindings.Add(GetMemberBinding("FirstName", pParam, "FirstName"));
            bindings.Add(GetMemberBinding("LastName", pParam, "LastName"));
 
            MemberInitExpression memberInitExpression =

System.Linq.Expressions.Expression.MemberInit(newExp, bindings);

 
            Expression<Func<Person, FileFormat>> selector =

(Expression<Func<Person, FileFormat>>)BinaryExpression.Lambda(memberInitExpression, pParam);

 
            List<FileFormat> fileFormat = persons.Where(whereExp).Select(selector).ToList();
 
            Console.WriteLine(fileFormat.Count.ToString());
            Console.ReadLine();
        }
        static MemberBinding GetMemberBinding(string property, ParameterExpression param, string column)
        {
            MemberInfo memberInfo = typeof(FileFormat).GetMember(property)[0];
            MemberExpression memberExpression = LambdaExpression.PropertyOrField(param, column);
            return System.Linq.Expressions.Expression.Bind(memberInfo, memberExpression);
        }
    }
    public class Person
    {
        public int PersonID { get; set; }
        public int CompanyID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    public class FileFormat
    {
        public int PersonID { get; set; }
        public int CompanyID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int CoverageID { get; set; }
        public int ProductID { get; set; }
        public double CoverageAmount { get; set; }
        public double CoverageCost { get; set; }
        public DateTime CoverageDate { get; set; }
    }
 
}


As evident in the code in Listing 1.3, decisions can be made at run time to determine what should be in the where and the select clauses of the query. The final value of whereExp is p => (p.CompanyID = 1). The final value of selector is p => new FileFormat() {PersonID=p.PersonID, FirstName=p.Firstname, LastName=p.LastName}

2 comments:

  1. Very nice article. Can you let me know how to read ICollection or List in the entity?

    ReplyDelete
  2. Thanks a lot. This post helped me. I was looking for solution for dynamic select query about a week. Here I got a solution.

    Thanks
    Siva
    www.dotnetanalyst.com

    ReplyDelete