コード例 #1
0
        /// <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));
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        /// <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));
        }
コード例 #4
0
        /// <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));
        }
コード例 #5
0
        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));
        }
コード例 #6
0
 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);
     }
 }
コード例 #7
0
//		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);
            //}
        }
コード例 #8
0
    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);
    }
コード例 #9
0
        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));
        }
コード例 #10
0
        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);
        }
コード例 #11
0
    /// <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);
    }
コード例 #12
0
        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));
        }
コード例 #13
0
        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));
        }
コード例 #14
0
        /// <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));
        }
コード例 #15
0
 public void ShouldInstantiateConstructorWithNullParameter()
 {
     var parameterRebinder = new ParameterRebinder(null);
 }
コード例 #16
0
 public ValueCompare()
 {
     PE = Expression.Parameter(typeof(TEntity), "z");
     _parameterRebinder = new ParameterRebinder(PE);
 }
コード例 #17
0
 /// <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));
 }
コード例 #18
0
        //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);
        }