/// <summary> /// 以特定的条件运行组合两个Expression表达式 /// </summary> /// <typeparam name="T">表达式的主实体类型</typeparam> /// <param name="first">第一个Expression表达式</param> /// <param name="second">要组合的Expression表达式</param> /// <param name="merge">组合条件运算方式</param> /// <returns>组合后的表达式</returns> 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) Dictionary <ParameterExpression, ParameterExpression> 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 first Expression secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // apply composition of lambda expression bodies to parameters from the first expression return(Expression.Lambda <T>(merge(first.Body, secondBody), first.Parameters)); }
static Expression <T> Compose <T>(this Expression <T> first, Expression <T> second, Func <Expression, Expression, Expression> merge) { // zip parameters (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 the parameters in the first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // create a merged lambda expression with parameters from the first expression return(Expression.Lambda <T>(merge(first.Body, secondBody), first.Parameters)); }
/// <summary> /// Combines the first expression with the second using the specified merge function. /// </summary> static Expression <T> Compose <T>(this Expression <T> first, Expression <T> second, Func <Expression, Expression, Expression> merge) { // zip parameters (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 the parameters in the first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // create a merged lambda expression with parameters from the first expression return(Expression.Lambda <T>(merge(first.Body, secondBody), first.Parameters)); }
/// <summary> /// 拼接 and 条件语句 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public static Expression <Func <T, bool> > And <T>(this Expression <Func <T, bool> > first, Expression <Func <T, bool> > second) { if (first == null) { return(second); } if (second == null) { return(first); } return(ParameterRebinder.Compose(first, second, Expression.And)); }
public static Expression <Func <T, bool> > Compose <T>(this Expression <Func <T, bool> > first, string property, object value, Func <Expression, Expression, Expression> merge) { var type = typeof(T); var param = Expression.Parameter(type, "s"); var memberExpression = Expression.Property(param, property); var constantExpression = Expression.Constant(value); BinaryExpression expression = Expression.Equal(memberExpression, constantExpression); var map = first.Parameters.Select((f, i) => new { f, s = param }).ToDictionary(p => p.s, p => p.f); var secondBody = ParameterRebinder.ReplaceParameters(map, expression); return(Expression.Lambda <Func <T, bool> >(merge(first.Body, secondBody), first.Parameters)); }
public void Append(Expression <Func <TEntity, bool> > expressionPiece) { if (Expression == null) { Expression = expressionPiece; } else { var map = Expression.Parameters.Select((f, i) => new { f, s = expressionPiece.Parameters[i] }).ToDictionary(p => p.s, p => p.f); var invokedExpression = ParameterRebinder.ReplaceParameters(map, expressionPiece.Body); Expression = System.Linq.Expressions.Expression.Lambda <Func <TEntity, bool> > (System.Linq.Expressions.Expression.AndAlso(Expression.Body, invokedExpression), Expression.Parameters); } }
// public class JoinCond<T1,T2> // { // public JoinCond(Expression<Func<JoinClass<T1,T2>, bool>> JoinCond) { // myExpr = JoinCond; // } // #region equal expr //// public JoinCond(Expression<Func<T1, object>> T1_Property, Expression<Func<T2, object>> T2_Property) //// { //// if (T1_Property.Body.NodeType.Equals(ExpressionType.Convert)) //// { //// T1Property = ((T1_Property.Body as //// UnaryExpression).Operand as MemberExpression).Member.Name; //// } //// else //// { //// T1Property = (T1_Property.Body as //// MemberExpression).Member.Name; //// } //// if (T2_Property.Body.NodeType.Equals(ExpressionType.Convert)) //// { //// T2Property = ((T2_Property.Body as //// UnaryExpression).Operand as MemberExpression).Member.Name; //// } //// else //// { //// T2Property = (T2_Property.Body as //// MemberExpression).Member.Name; //// } //// } // #endregion // public string T1Property; // public string T2Property; // public Expression<Func<JoinClass<T1,T2>, bool>> myExpr = null; // } public static IQueryable <JoinClass <T1, T2> > MultiJoin <T1, T2> ( MyContext db, Expression <Func <JoinClass <T1, T2>, bool> > JoinCond ) where T2 : class where T1 : class { var jfb = Expression.Parameter(typeof(JoinClass <T1, T2>), "jfb"); FieldInfo ItemT1 = typeof(JoinClass <T1, T2>).GetField("t1"); FieldInfo ItemT2 = typeof(JoinClass <T1, T2>).GetField("t2"); var pb = Expression.Field(jfb, ItemT1); // var pf = Expression.Field(jfb, ItemT2); // var old_expr = JoinCond; var map = old_expr.Parameters.ToDictionary(p => p, p => jfb); var reboundBody = ParameterRebinder.ReplaceParameters(map, old_expr.Body); var newCond = Expression.Lambda <Func <JoinClass <T1, T2>, bool> >(reboundBody, jfb).Body; var WhereExpr = Expression.Lambda <Func <JoinClass <T1, T2>, bool> >(newCond, jfb); //using (var db = new MyContext()) { var qx = db.GetTable <T1>() .SelectMany( b => db.GetTable <T2>() , (b, f) => new JoinClass <T1, T2>() { t1 = b, t2 = f }); //Translated Above from Query (or Query Expression) to Method Chaining (or Fluent) //var qxExe = qx.ToArray(); //Console.WriteLine(String.Format("Last QX: {0}", db.LastQuery)); //var q = from b in db.GetTable<T1>() // from f in db.GetTable<T2>() // select new JoinClass<T1, T2>() { t1 = b, t2 = f }; var w = qx.Where(WhereExpr); #region only for debugging purposes - to be deleted //w.ToArray(); //Console.WriteLine(String.Format("Last Query: {0}",db.LastQuery)); #endregion return(w); //} }
private LambdaExpression CreateExpression(Expression <Func <Entity, bool> > condition, Type type) { var lambda = (LambdaExpression)condition; if (!typeof(Entity).IsAssignableFrom(type)) { return(null); } var newParams = new[] { Expression.Parameter(type, "entity") }; var paramMap = lambda.Parameters.Select((original, i) => new { original, replacement = newParams[i] }).ToDictionary(p => p.original, p => p.replacement); var fixedBody = ParameterRebinder.ReplaceParameters(paramMap, lambda.Body); lambda = Expression.Lambda(fixedBody, newParams); return(lambda); }
private static Expression <T> Compose <T>( this Expression <T> first, Expression <T> second, Func <Expression, Expression, Expression> merge) { var map = first.Parameters .Select((f, i) => new { f, s = second.Parameters[i] }) .ToDictionary(p => p.s, p => p.f); var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); return(Expression.Lambda <T>(merge(first.Body, secondBody), first.Parameters)); }
public static Expression <Func <T, bool> > CreateIsAfterFilter <T>( Expression <Func <T, DateTimeOffset> > getTimestampFromItem, DateTimeOffset timestampExclusive) { // Translate Expression<Func<T, DateTime>> to Expression<Func<T, bool>> // aka Translate 'get date for item' to 'is newer than last cache date' var inputParameter = Expression.Parameter(typeof(T), "a"); //Expression getTimestampExpression; //if (getTimestampFromItem.Body is MemberExpression) //{ // //getTimestampExpression = Expression.Lambda<Func<DateTimeOffset>>(getTimestampFromItem, inputParameter); // //getTimestampExpression = Expression.Invoke(getTimestampFromItem, inputParameter); // getTimestampExpression = Expression.Lambda(getTimestampFromItem.Body, inputParameter); //} //else //{ // getTimestampExpression = Expression.Invoke(getTimestampFromItem, inputParameter); //} ////var nullValue = Expression.Constant(null, typeof(DateTime?)); ////var isNotNull = Expression.NotEqual(getTimestampExpression, nullValue); //var dateValue = Expression.Constant(timestampExclusive, typeof(DateTimeOffset)); //var isAfterDate = Expression.GreaterThan(getTimestampExpression, dateValue); ////var and = Expression.And(isNotNull, isAfterDate); //Expression<Func<T, bool>> isAfterDateLambda = Expression.Lambda<Func<T, bool>>(isAfterDate, inputParameter); var isAfterDateLambda = Expression.Lambda <Func <T, bool> >( Expression.GreaterThan( ParameterRebinder.ReplaceParameters( getTimestampFromItem.Parameters.ToDictionary(p => p, p => inputParameter), getTimestampFromItem.Body), Expression.Constant(timestampExclusive, typeof(DateTimeOffset))), inputParameter); ; Expression isAfterFilter = isAfterDateLambda.Body; return(isAfterDateLambda); }
/// <summary> /// Adapt a QueryConditional to the member we're currently visiting. /// </summary> /// <param name="condition">The condition to adapt</param> /// <param name="type">The type of the current member (=Navigation property)</param> /// <returns>The adapted QueryConditional</returns> private LambdaExpression CreateExpression(Expression <Func <ITranslation, bool> > condition, Type type) { var lambda = (LambdaExpression)condition; var conditionType = condition.GetType().GetGenericArguments().First().GetGenericArguments().First(); // Only continue when the condition is applicable to the Type of the member if (conditionType == null) { return(null); } if (!conditionType.IsAssignableFrom(type)) { return(null); } var newParams = new[] { Expression.Parameter(type, "bo") }; var paramMap = lambda.Parameters.Select((original, i) => new { original, replacement = newParams[i] }).ToDictionary(p => p.original, p => p.replacement); var fixedBody = ParameterRebinder.ReplaceParameters(paramMap, lambda.Body); lambda = Expression.Lambda(fixedBody, newParams); return(lambda); }
private static Expression <T> Compose <T>(Expression <T> first, Expression <T> second, Func <Expression, Expression, Expression> merge) { if (first == null) { throw new ArgumentNullException(nameof(first)); } if (second == null) { throw new ArgumentNullException(nameof(second)); } // 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 first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // apply composition of lambda expression bodies to parameters from the first expression return(Expression.Lambda <T>(merge(first.Body, secondBody), first.Parameters)); }
public static LambdaExpression Compose(this LambdaExpression first, LambdaExpression second, Func <Expression, Expression, Expression> merge) { if (first == null) { throw new ArgumentNullException("first"); } if (second == null) { throw new ArgumentNullException("second"); } if (merge == null) { throw new ArgumentNullException("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 first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // apply composition of lambda expression bodies to parameters from the first expression return(Expression.Lambda(first.Type, merge(first.Body, secondBody), first.Parameters)); }
/// <summary> /// 以特定的条件运行组合两个Expression表达式 /// </summary> /// <typeparam name="T">表达式的主实体类型</typeparam> /// <param name="first">第一个Expression表达式</param> /// <param name="second">要组合的Expression表达式</param> /// <param name="merge">组合条件运算方式</param> /// <returns>组合后的表达式</returns> public static Expression <T> Compose <T>(this Expression <T> first, Expression <T> second, Func <Expression, Expression, Expression> merge) { if (!new NotNull().IsValid(first)) { throw new ArgumentNullException(nameof(first)); } if (!new NotNull().IsValid(second)) { throw new ArgumentNullException(nameof(second)); } if (!new NotNull().IsValid(second)) { throw new ArgumentNullException(nameof(second)); } var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); return(Expression.Lambda <T>(merge(first.Body, secondBody), first.Parameters)); }
public void ShouldInstantiateConstructorWithNullParameter() { var parameterRebinder = new ParameterRebinder(null); }
public ValueCompare() { PE = Expression.Parameter(typeof(TEntity), "z"); _parameterRebinder = new ParameterRebinder(PE); }
/// <summary> /// Or 条件语句 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="first">条件1</param> /// <param name="second">条件2</param> /// <returns></returns> public static Expression <Func <T, bool> > Or <T>(this Expression <Func <T, bool> > first, Expression <Func <T, bool> > second) { return(ParameterRebinder.Compose(first, second, Expression.Or)); }
//public class UserClass2 //{ // public Bar b; // public Foo f; //} //public class UserClass3 //{ // public Bar b; // public Foo f; // public Qux q; //} //public static IQueryable<JoinClass<T1, T2, T3>> UserJoin<T, T1, T2, T3>( // MyContext db, // Expression<Func<JoinClass<T1, T2, T3>, bool>> JoinCond //) // where T : class // where T3 : class // where T2 : class // where T1 : class //{ // var jfb = Expression.Parameter(typeof(T), "jfb"); // FieldInfo[] ItemsT = typeof(T).GetFields(); // MemberExpression[] pars = ItemsT.Select(item => Expression.Field(jfb, item)).ToArray(); // var old_expr = JoinCond; // var map = old_expr.Parameters.ToDictionary(p => p, p => jfb); // var reboundBody = ParameterRebinder.ReplaceParameters(map, old_expr.Body); // var newCond = Expression.Lambda(reboundBody, jfb).Body; // var WhereExpr = Expression.Lambda<Func<JoinClass<T1, T2, T3>, bool>>(newCond, jfb); // Type[] types = ItemsT.Select(item => item.FieldType).ToArray(); // MethodInfo method = typeof(LinqToDB.Data.DataConnection).GetMethods()[32]; // MethodInfo[] generic = types.Select(t => method.MakeGenericMethod(t) ).ToArray(); // object[] tables = generic.Select(g => g.Invoke(db, null)).ToArray(); // var qx = ((IQueryable<T1>)tables[0]) // .SelectMany( // b => db.GetTable<T2>(), (b, f) => new JoinClass<T1, T2>() { t1 = b, t2 = f }) // .SelectMany( // q => db.GetTable<T3>() // , (j, q) => new JoinClass<T1, T2, T3>() { t1 = j.t1, t2 = j.t2, t3 = q }); // return qx.Where(WhereExpr); //} public static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine("by Id int"); using (var db = new MyContext()) { var queryJoinById = MultiJoin <Bar, Foo>(db, j => j.t1.id == j.t2.id); //Test.NewJoin<Bar, Foo, int, Tuple<Bar,Foo>>(q => q.id, b => b.id, (f, b) => new Tuple<Bar,Foo>(b,f)); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); ConsoleOut(queryJoinById); Console.WriteLine("-------------"); Console.WriteLine("by Col string"); var queryJoinByCol = MultiJoin <Bar, Foo>(db, j => j.t2.ColFoo.StartsWith(j.t1.ColBar)); //Test.NewJoin<Bar, Foo, string, Tuple<Bar,Foo>>(q => q.ColFoo, b => b.ColBar, (f, b) => new Tuple<Bar,Foo>(b,f)); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); ConsoleOut(queryJoinByCol); Console.WriteLine("-------------"); Console.WriteLine("by Col string AND Id int"); var w = MultiJoin <Bar, Foo>(db, j => j.t2.ColFoo.StartsWith(j.t1.ColBar) && j.t1.id == j.t2.id ); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); ConsoleOut(w); //.Select(j => new Tuple<Bar,Foo>(j.t1,j.t2)) var test = MultiJoin <Bar, Qux>(db, j => j.t1.id == j.t2.id && !j.t2.Success ); Console.WriteLine(String.Join(",", test.Select(t => t.t1.Name) ) ); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); var complex = MultiJoin <Bar, Foo, Qux, Baz>(db, j => (j.t2.id == 0 || j.t2.ColFoo.StartsWith(j.t1.ColBar)) && j.t1.id == j.t3.id && !j.t3.Success && j.t4.id == j.t1.id ); Console.WriteLine(String.Join(",", complex.Select(t => t.t1.Name + "@" + t.t2.FromDate.ToShortDateString() + "*" + t.t4.Sex) ) ); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); var left = db.GetTable <Bar>() .SelectMany( b => db.GetTable <Baz>().Where(x => x.id == b.id).DefaultIfEmpty() , (b, f) => new JoinClass <Bar, Baz>() { t1 = b, t2 = f }); Console.WriteLine(String.Join(",", left.Select(t => t.t1.Name + "*" + (t.t2 == null ? "-" : t.t2.Sex.Equals('M')?"M":"F")) ) ); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); var linqjoin = db.GetTable <Bar>().Join(db.GetTable <Baz>(), x => x.id, y => y.id, (x, y) => new { x, y }).ToArray(); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); var qleft = from b in db.GetTable <Bar>() join z in db.GetTable <Baz>() on b.id equals z.id into g from s in g.DefaultIfEmpty() select new { b, s }; qleft.ToArray(); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); var nonqleft = db.GetTable <Bar>().GroupJoin(db.GetTable <Baz>(), x => x.id, y => y.id, (x, y) => new { x, y }) .SelectMany(t => t.y.DefaultIfEmpty() , (o, i) => new { Outer = o.x, Inner = i }) .ToArray(); Console.WriteLine(String.Format("Last Query: {0}", db.LastQuery)); Console.WriteLine(String.Join(",", nonqleft.Select(t => t.Outer.Name + "*" + (t.Inner == null ? "-" : t.Inner.Sex.Equals('M') ? "M" : "F")) ) ); //var super = UserJoin< UserClass3, Bar, Foo, Qux>(db, // j => j.f.ColFoo.StartsWith(j.b.ColBar) && j.f.id == j.q.id && j.q.Success // ); } #region SO try to generalize the Equal Expr into LambdaExpr in the generic JoinCond //I have this expression Expression <Func <Bar, bool> > old_expr = x => x.Name == x.ColBar; //I want to change parameter from x to y //I already have the y parameter in the code, let's say it is the followinf ParameterExpression py = Expression.Parameter(typeof(Bar), "y"); //this is what I have tried, but it is *not* complete neither generic Expression expr_to_do; if (old_expr.Body.NodeType.Equals(ExpressionType.Convert)) { UnaryExpression convEx = old_expr.Body as UnaryExpression; expr_to_do = convEx.Operand; } else { expr_to_do = old_expr.Body; } //TODO convert the BinarayExpression eqEx, etc... etc... if (expr_to_do.NodeType.Equals(ExpressionType.Equal)) { // have I to manage each Expr Type case?? var eqExpr = expr_to_do as BinaryExpression; var left = eqExpr.Left as MemberExpression; //... //var new_left = Expression.Property(...,py) } var newLambda = Expression.Lambda(expr_to_do, new ParameterExpression[1] { py }); var map = old_expr.Parameters.ToDictionary(p => p, p => py); var reboundBody = ParameterRebinder.ReplaceParameters(map, old_expr.Body); var lambda = Expression.Lambda <Func <Bar, bool> >(reboundBody, py); //newLambda = Expression.Lambda(Expression.Call( // old_expr.Compile().Method, new Expression[] {Expression.Constant(new Bar()),Expression.Constant(new Bar())}) // ,new ParameterExpression[1]{py}); //Again, what I want to get is the following where y *is* the parameter defined *above* Expression <Func <Bar, bool> > new_expr = y => y.Name == y.ColBar; //The code/method I'm looking for - if it does exist a method to do that - must be generic enough not specific to this single expression #endregion Console.Write("Press any key to continue . . . "); Console.ReadKey(true); }