肖恩D++
Not Equal C && !=C && 不等于西
-
Predicates in Lambda Expression for Entity Framework Code First
Posted on July 24th, 2013 1 commentIf I have 2 entities of “People” and “Car”, and “1” People can have “Many” Car, my code first class could be like below:
12345678910111213141516171819public class People{[key]public int ID { get; set; }public string Name { get; set; }public virtual ICollection<Car> Cars { get; set; }}public class Car{[key]public string VIN { get; set; }public string Maker { get; set; }public int OwnerID { get; set; }[ForeignKey("OwnerID")]public virtual People Owner { get; set; }}
Let’s say, if we want to find the person who name is “Sean”, and has a car of maker “GMC” by using lambda Predicates, we probably need to do like below:1234567891011using System;using System.Linq;using System.Linq.Expressions;using System.Collections.Generic;...Entities context = new Entities();//DBContext objectExpression<Func<People, bool>> pLambda = x => x.Name == "Sean";Expression<Func<Car, bool>> cLambda = x => x.Maker == "GMC";List<People> result = context.People.Where(pLambda).Where(x => x.Cars.AsQueryable().Any(cLambda)).ToList();What if I want to compose above 2 lambda to 1? Unfortunately there is no easy way to simply join multiple lambda by whatever “AND” or “OR”, specially if navigation properties involved like the example above.
From Colin Meek’s Blog, we can manually write a general utility method to compose lambda expressions1234567891011121314151617181920212223242526272829303132333435363738394041public static class Utility {public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) {// build parameter map (from parameters of second to parameters of first)var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);// replace parameters in the second lambda expression with parameters from the firstvar secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);// apply composition of lambda expression bodies to parameters from the first expressionreturn Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);}public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {return first.Compose(second, Expression.And);}public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {return first.Compose(second, Expression.Or);}}//Important rebinder to merge different parameters from multiple lambdapublic class ParameterRebinder : ExpressionVisitor {private readonly Dictionary<ParameterExpression, ParameterExpression> map;public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) {this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();}public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) {return new ParameterRebinder(map).Visit(exp);}protected override Expression VisitParameter(ParameterExpression p) {ParameterExpression replacement;if (map.TryGetValue(p, out replacement)) {p = replacement;}return base.VisitParameter(p);}}By using this utility, we can write our code simply like below
12345Entities context = new Entities();//DBContext objectExpression<Func<People, bool>> pLambda = x => x.Name == "Sean";Expression<Func<Car, bool>> cLambda = x => x.Maker == "GMC";pLambda = pLambda.And(x => x.Cars.AsQueryable().Any(cLambda));List<People> result = context.People.Where(pLambda).ToList();
Leave a Reply
1 Comment on "Predicates in Lambda Expression for Entity Framework Code First"
I read a lot of interesting posts here. Probably you spend a lot of time writing, i know how to save you a lot of time, there is
an online tool that creates high quality, SEO friendly articles in minutes,
just type in google – laranitas free content source