Esempio n. 1
0
            protected override SqlStatement ProcessQuery(SqlStatement statement)
            {
                if (statement.IsInsert() && statement.RequireInsertClause().Into.Name == "Parent")
                {
                    var expr =
                        QueryVisitor.Find(statement.RequireInsertClause(), e =>
                    {
                        if (e.ElementType == QueryElementType.SetExpression)
                        {
                            var se = (SqlSetExpression)e;
                            return(((SqlField)se.Column).Name == "ParentID");
                        }

                        return(false);
                    }) as SqlSetExpression;

                    if (expr != null)
                    {
                        var value = ConvertTo <int> .From(((IValueContainer)expr.Expression).Value);

                        if (value == 555)
                        {
                            var tableName = "Parent1";
                            var dic       = new Dictionary <IQueryElement, IQueryElement>();

                            statement = new QueryVisitor().Convert(statement, e =>
                            {
                                if (e.ElementType == QueryElementType.SqlTable)
                                {
                                    var oldTable = (SqlTable)e;

                                    if (oldTable.Name == "Parent")
                                    {
                                        var newTable = new SqlTable(oldTable)
                                        {
                                            Name = tableName, PhysicalName = tableName
                                        };

                                        foreach (var field in oldTable.Fields.Values)
                                        {
                                            dic.Add(field, newTable.Fields[field.Name]);
                                        }

                                        return(newTable);
                                    }
                                }

                                IQueryElement ex;
                                return(dic.TryGetValue(e, out ex) ? ex : null);
                            });
                        }
                    }

                    return(statement);
                }

                return(statement);
            }
Esempio n. 2
0
        public async Task BasicOperationsAsync([IncludeDataSources(ProviderName.SQLiteMS)] string context, [Values("Value1", "Value2")] string columnName)
        {
            var ms = CreateMappingSchema(columnName);

            using (var db = GetDataContext(context, ms))
                using (var table = db.CreateLocalTable <SampleClass>())
                    using (db.CreateLocalTable <SampleClassWithIdentity>())
                    {
                        await db.InsertAsync(new SampleClass()
                        {
                            Id = 1, StrKey = "K1", Value = "V1"
                        });

                        await db.InsertAsync(new SampleClass()
                        {
                            Id = 2, StrKey = "K2", Value = "V2"
                        });

                        await db.InsertOrReplaceAsync(new SampleClass()
                        {
                            Id = 3, StrKey = "K3", Value = "V3"
                        });

                        await db.InsertWithIdentityAsync(new SampleClassWithIdentity()
                        {
                            Value = "V4"
                        });

                        await db.DeleteAsync(new SampleClass()
                        {
                            Id = 1, StrKey = "K1"
                        });

                        await db.UpdateAsync(new SampleClass()
                        {
                            Id = 2, StrKey = "K2", Value = "VU"
                        });

                        var found = null != QueryVisitor.Find(table.GetSelectQuery(),
                                                              e => e is SqlField f && f.PhysicalName == columnName);

                        var foundKey = null != QueryVisitor.Find(table.GetSelectQuery(),
                                                                 e => e is SqlField f && f.PhysicalName == columnName);

                        Assert.IsTrue(found);
                        Assert.IsTrue(foundKey);

                        var result = await table.ToArrayAsync();
                    }
        }
Esempio n. 3
0
        static bool CheckColumn(SelectQuery.Column column, ISqlExpression expr, SelectQuery query, bool optimizeValues, bool optimizeColumns)
        {
            if (expr is SqlField || expr is SelectQuery.Column)
            {
                return(false);
            }

            if (expr is SqlValue)
            {
                return(!optimizeValues && 1.Equals(((SqlValue)expr).Value));
            }

            if (expr is SqlBinaryExpression)
            {
                var e = (SqlBinaryExpression)expr;

                if (e.Operation == "*" && e.Expr1 is SqlValue)
                {
                    var value = (SqlValue)e.Expr1;

                    if (value.Value is int && (int)value.Value == -1)
                    {
                        return(CheckColumn(column, e.Expr2, query, optimizeValues, optimizeColumns));
                    }
                }
            }

            var visitor = new QueryVisitor();

            if (optimizeColumns &&
                visitor.Find(expr, e => e is SelectQuery || IsAggregationFunction(e)) == null)
            {
                var n = 0;
                var q = query.ParentSelect ?? query;

                visitor.VisitAll(q, e => { if (e == column)
                                           {
                                               n++;
                                           }
                                 });

                return(n > 2);
            }

            return(true);
        }
Esempio n. 4
0
        public void Issue95Test()
        {
            using (var db = new TestDataConnection())
            {
                var q   = db.GetTable <Issue95Entity>().Where(_ => _.EnumValue == TinyIntEnum.Value1);
                var ctx = q.GetMyContext();
                Assert.IsNull(QueryVisitor.Find(ctx.SelectQuery.Where, _ => _.ElementType == QueryElementType.SqlExpression), db.GetSqlText(ctx.SelectQuery));

                q   = db.GetTable <Issue95Entity>().Where(_ => TinyIntEnum.Value1 == _.EnumValue);
                ctx = q.GetMyContext();
                Assert.IsNull(QueryVisitor.Find(ctx.SelectQuery.Where, _ => _.ElementType == QueryElementType.SqlExpression), db.GetSqlText(ctx.SelectQuery));

                var p = TinyIntEnum.Value2;

                q   = db.GetTable <Issue95Entity>().Where(_ => _.EnumValue == p);
                ctx = q.GetMyContext();
                Assert.IsNull(QueryVisitor.Find(ctx.SelectQuery.Where, _ => _.ElementType == QueryElementType.SqlExpression), db.GetSqlText(ctx.SelectQuery));

                q   = db.GetTable <Issue95Entity>().Where(_ => p == _.EnumValue);
                ctx = q.GetMyContext();
                Assert.IsNull(QueryVisitor.Find(ctx.SelectQuery.Where, _ => _.ElementType == QueryElementType.SqlExpression), db.GetSqlText(ctx.SelectQuery));
            }
        }
Esempio n. 5
0
        static bool CheckColumn(SelectQuery.Column column, ISqlExpression expr, SelectQuery query, bool optimizeValues, bool optimizeColumns)
        {
            if (expr is SqlField || expr is SelectQuery.Column)
                return false;

            if (expr is SqlValue)
                return !optimizeValues && 1.Equals(((SqlValue)expr).Value);

            if (expr is SqlBinaryExpression)
            {
                var e = (SqlBinaryExpression)expr;

                if (e.Operation == "*" && e.Expr1 is SqlValue)
                {
                    var value = (SqlValue)e.Expr1;

                    if (value.Value is int && (int)value.Value == -1)
                        return CheckColumn(column, e.Expr2, query, optimizeValues, optimizeColumns);
                }
            }

            var visitor = new QueryVisitor();

            if (optimizeColumns &&
                visitor.Find(expr, e => e is SelectQuery || IsAggregationFunction(e)) == null)
            {
                var n = 0;
                var q = query.ParentSelect ?? query;

                visitor.VisitAll(q, e => { if (e == column) n++; });

                return n > 2;
            }

            return true;
        }
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence           = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var resultSelector     = (LambdaExpression)methodCall.Arguments[2].Unwrap();

            if (!sequence.SelectQuery.GroupBy.IsEmpty ||
                sequence.SelectQuery.Select.TakeValue != null ||
                sequence.SelectQuery.Select.SkipValue != null ||
                sequence.SelectQuery.Select.IsDistinct)
            {
                sequence = new SubQueryContext(sequence);
            }

            var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence);
            var expr    = collectionSelector.Body.Unwrap();

            var collectionInfo = new BuildInfo(context, expr, new SelectQuery());
            var collection     = builder.BuildSequence(collectionInfo);
            var leftJoin       = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext || collectionInfo.JoinType == SelectQuery.JoinType.Left;
            var sql            = collection.SelectQuery;

            var sequenceTables = new HashSet <ISqlTableSource>(sequence.SelectQuery.From.Tables[0].GetTables());
            var newQuery       = null != QueryVisitor.Find(sql, e => e == collectionInfo.SelectQuery);
            var crossApply     = null != QueryVisitor.Find(sql, e =>
                                                           e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) ||
                                                           e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) ||
                                                           e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SelectQuery.Column)e).Parent));

            if (collection is JoinBuilder.GroupJoinSubQueryContext)
            {
                var groupJoin = ((JoinBuilder.GroupJoinSubQueryContext)collection).GroupJoin;

                groupJoin.SelectQuery.From.Tables[0].Joins[0].JoinType = SelectQuery.JoinType.Inner;
                groupJoin.SelectQuery.From.Tables[0].Joins[0].IsWeak   = false;
            }

            if (!newQuery)
            {
                if (collection.SelectQuery.Select.HasModifier)
                {
                    if (crossApply)
                    {
                        var foundJoin = context.SelectQuery.FindJoin(j => j.Table.Source == collection.SelectQuery);
                        if (foundJoin != null)
                        {
                            foundJoin.JoinType = leftJoin ? SelectQuery.JoinType.OuterApply : SelectQuery.JoinType.CrossApply;

                            collection.SelectQuery.Where.ConcatSearchCondition(foundJoin.Condition);

                            ((ISqlExpressionWalkable)collection.SelectQuery.Where).Walk(false, e =>
                            {
                                var column = e as SelectQuery.Column;
                                if (column != null)
                                {
                                    if (column.Parent == collection.SelectQuery)
                                    {
                                        return(column.UnderlyingColumn);
                                    }
                                }
                                return(e);
                            });

                            foundJoin.Condition.Conditions.Clear();
                        }
                    }
                }

                context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }

            if (!crossApply)
            {
                if (!leftJoin)
                {
                    context.Collection = new SubQueryContext(collection, sequence.SelectQuery, true);
                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
                else
                {
                    var join = SelectQuery.OuterApply(sql);
                    sequence.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                    context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);

                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
            }

            var joinType = collectionInfo.JoinType;

            if (collection is TableBuilder.TableContext)
            {
//				if (collectionInfo.IsAssociationBuilt)
//				{
//					context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);
//					return new SelectContext(buildInfo.Parent, resultSelector, sequence, context);
//				}

                if (joinType == SelectQuery.JoinType.Auto)
                {
                    var table       = (TableBuilder.TableContext)collection;
                    var isApplyJoin = collection.SelectQuery.Select.HasModifier ||
                                      table.SqlTable.TableArguments != null && table.SqlTable.TableArguments.Length > 0;

                    joinType = isApplyJoin
                                                ? (leftJoin ? SelectQuery.JoinType.OuterApply : SelectQuery.JoinType.CrossApply)
                                                : (leftJoin ? SelectQuery.JoinType.Left : SelectQuery.JoinType.Inner);
                }

                var join = CreateJoin(joinType, sql);
                join.JoinedTable.CanConvertApply = false;

                if (!(joinType == SelectQuery.JoinType.CrossApply || joinType == SelectQuery.JoinType.OuterApply))
                {
                    join.JoinedTable.Condition.Conditions.AddRange(sql.Where.SearchCondition.Conditions);
                    sql.Where.SearchCondition.Conditions.Clear();
                }

                var collectionParent = collection.Parent as TableBuilder.TableContext;

                // Association.
                //
                if (collectionParent != null && collectionInfo.IsAssociationBuilt)
                {
                    var ts = (SelectQuery.TableSource)QueryVisitor.Find(sequence.SelectQuery.From, e =>
                    {
                        if (e.ElementType == QueryElementType.TableSource)
                        {
                            var t = (SelectQuery.TableSource)e;
                            return(t.Source == collectionParent.SqlTable);
                        }

                        return(false);
                    });

                    ts.Joins.Add(join.JoinedTable);
                }
                else
                {
                    //if (collectionInfo.IsAssociationBuilt)
                    //{
                    //	collectionInfo.AssosiationContext.ParentAssociationJoin.IsWeak = false;
                    //}
                    //else
                    {
                        sequence.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                    }
                }

                context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }
            else
            {
                if (joinType == SelectQuery.JoinType.Auto)
                {
                    joinType = leftJoin ? SelectQuery.JoinType.OuterApply : SelectQuery.JoinType.CrossApply;
                }

                var join = CreateJoin(joinType, sql);

                if (!(joinType == SelectQuery.JoinType.CrossApply || joinType == SelectQuery.JoinType.OuterApply))
                {
                    join.JoinedTable.Condition.Conditions.AddRange(sql.Where.SearchCondition.Conditions);
                    sql.Where.SearchCondition.Conditions.Clear();
                }

                sequence.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);

                context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }
        }
Esempio n. 7
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence           = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var resultSelector     = (LambdaExpression)methodCall.Arguments[2].Unwrap();

            if (sequence.SelectQuery.HasUnion || !sequence.SelectQuery.IsSimple)
            {
                sequence = new SubQueryContext(sequence);
            }

            var expr = collectionSelector.Body.Unwrap();

            DefaultIfEmptyBuilder.DefaultIfEmptyContext defaultIfEmpty = null;
            if (expr is MethodCallExpression mc && AllJoinsBuilder.IsMatchingMethod(mc, true))
            {
                defaultIfEmpty          = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, sequence, null);
                defaultIfEmpty.Disabled = true;
                sequence = new SubQueryContext(defaultIfEmpty);
            }

            var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence);

            context.SetAlias(collectionSelector.Parameters[0].Name);

            var collectionInfo = new BuildInfo(context, expr, new SelectQuery());
            var collection     = builder.BuildSequence(collectionInfo);

            if (resultSelector.Parameters.Count > 1)
            {
                collection.SetAlias(resultSelector.Parameters[1].Name);
            }

            if (defaultIfEmpty != null && (collectionInfo.JoinType == JoinType.Right || collectionInfo.JoinType == JoinType.Full))
            {
                defaultIfEmpty.Disabled = false;
            }

            var leftJoin = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext || collectionInfo.JoinType == JoinType.Left;
            var sql      = collection.SelectQuery;

            var sequenceTables = new HashSet <ISqlTableSource>(sequence.SelectQuery.From.Tables[0].GetTables());
            var newQuery       = null != QueryVisitor.Find(sql, e => e == collectionInfo.SelectQuery);
            var crossApply     = null != QueryVisitor.Find(sql, e =>
                                                           e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) ||
                                                           e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) ||
                                                           e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SqlColumn)e).Parent));

            if (collection is JoinBuilder.GroupJoinSubQueryContext queryContext)
            {
                var groupJoin = queryContext.GroupJoin;

                groupJoin.SelectQuery.From.Tables[0].Joins[0].JoinType = JoinType.Inner;
                groupJoin.SelectQuery.From.Tables[0].Joins[0].IsWeak   = false;
            }

            if (!newQuery)
            {
                if (collection.SelectQuery.Select.HasModifier)
                {
                    if (crossApply)
                    {
                        var foundJoin = context.SelectQuery.FindJoin(j => j.Table.Source == collection.SelectQuery);
                        if (foundJoin != null)
                        {
                            foundJoin.JoinType = leftJoin ? JoinType.OuterApply : JoinType.CrossApply;

                            collection.SelectQuery.Where.ConcatSearchCondition(foundJoin.Condition);

                            ((ISqlExpressionWalkable)collection.SelectQuery.Where).Walk(new WalkOptions(), e =>
                            {
                                if (e is SqlColumn column)
                                {
                                    if (column.Parent == collection.SelectQuery)
                                    {
                                        return(column.UnderlyingColumn);
                                    }
                                }
                                return(e);
                            });

                            foundJoin.Condition.Conditions.Clear();
                        }
                    }
                }

                context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }

            if (!crossApply)
            {
                if (!leftJoin)
                {
                    context.Collection = new SubQueryContext(collection, sequence.SelectQuery, true);
                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
                else
                {
                    var join = sql.OuterApply();
                    sequence.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                    context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);

                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
            }

            void MoveSearchConditionsToJoin(SqlFromClause.Join join)
            {
                var tableSources = new HashSet <ISqlTableSource>();

                ((ISqlExpressionWalkable)sql.Where.SearchCondition).Walk(new WalkOptions(), e =>
                {
                    if (e is ISqlTableSource ts && !tableSources.Contains(ts))
                    {
                        tableSources.Add(ts);
                    }
                    return(e);
                });

                bool ContainsTable(ISqlTableSource tbl, IQueryElement qe)
                {
                    return(null != QueryVisitor.Find(qe, e =>
                                                     e == tbl ||
                                                     e.ElementType == QueryElementType.SqlField && tbl == ((SqlField)e).Table ||
                                                     e.ElementType == QueryElementType.Column && tbl == ((SqlColumn)e).Parent));
                }

                var conditions = sql.Where.SearchCondition.Conditions;

                if (conditions.Count > 0)
                {
                    for (var i = conditions.Count - 1; i >= 0; i--)
                    {
                        var condition = conditions[i];

                        if (!tableSources.Any(ts => ContainsTable(ts, condition)))
                        {
                            join.JoinedTable.Condition.Conditions.Insert(0, condition);
                            conditions.RemoveAt(i);
                        }
                    }
                }
            }
Esempio n. 8
0
		void MoveCountSubQuery(IQueryElement element)
		{
			if (element.ElementType != QueryElementType.SqlQuery)
				return;

			var query = (SelectQuery)element;

			for (var i = 0; i < query.Select.Columns.Count; i++)
			{
				var col = query.Select.Columns[i];

				// The column is a subquery.
				//
				if (col.Expression.ElementType == QueryElementType.SqlQuery)
				{
					var subQuery = (SelectQuery)col.Expression;
					var isCount  = false;

					// Check if subquery is Count subquery.
					//
					if (subQuery.Select.Columns.Count == 1)
					{
						var subCol = subQuery.Select.Columns[0];

						if (subCol.Expression.ElementType == QueryElementType.SqlFunction)
							isCount = ((SqlFunction)subCol.Expression).Name == "Count";
					}

					if (!isCount)
						continue;

					// Check if subquery where clause does not have ORs.
					//
					SelectQueryOptimizer.OptimizeSearchCondition(subQuery.Where.SearchCondition);

					var allAnd = true;

					for (var j = 0; allAnd && j < subQuery.Where.SearchCondition.Conditions.Count - 1; j++)
					{
						var cond = subQuery.Where.SearchCondition.Conditions[j];

						if (cond.IsOr)
							allAnd = false;
					}

					if (!allAnd || !ConvertCountSubQuery(subQuery))
						continue;

					// Collect tables.
					//
					var allTables   = new HashSet<ISqlTableSource>();
					var levelTables = new HashSet<ISqlTableSource>();

					new QueryVisitor().Visit(subQuery, e =>
					{
						if (e is ISqlTableSource source)
							allTables.Add(source);
					});

					new QueryVisitor().Visit(subQuery, e =>
					{
						if (e is ISqlTableSource source)
							if (subQuery.From.IsChild(source))
								levelTables.Add(source);
					});

					bool CheckTable(IQueryElement e)
					{
						switch (e.ElementType)
						{
							case QueryElementType.SqlField : return !allTables.Contains(((SqlField) e).Table);
							case QueryElementType.Column   : return !allTables.Contains(((SqlColumn)e).Parent);
						}

						return false;
					}

					var join = subQuery.LeftJoin();

					query.From.Tables[0].Joins.Add(join.JoinedTable);

					for (var j = 0; j < subQuery.Where.SearchCondition.Conditions.Count; j++)
					{
						var cond = subQuery.Where.SearchCondition.Conditions[j];

						if (QueryVisitor.Find(cond, CheckTable) == null)
							continue;

						var replaced = new Dictionary<IQueryElement,IQueryElement>();

						var nc = new QueryVisitor().Convert(cond, e =>
						{
							var ne = e;

							switch (e.ElementType)
							{
								case QueryElementType.SqlField :
									if (replaced.TryGetValue(e, out ne))
										return ne;

									if (levelTables.Contains(((SqlField)e).Table))
									{
										subQuery.GroupBy.Expr((SqlField)e);
										ne = subQuery.Select.Columns[subQuery.Select.Add((SqlField)e)];
									}

									break;

								case QueryElementType.Column   :
									if (replaced.TryGetValue(e, out ne))
										return ne;

									if (levelTables.Contains(((SqlColumn)e).Parent))
									{
										subQuery.GroupBy.Expr((SqlColumn)e);
										ne = subQuery.Select.Columns[subQuery.Select.Add((SqlColumn)e)];
									}

									break;
							}

							if (!ReferenceEquals(e, ne))
								replaced.Add(e, ne);

							return ne;
						});

						if (nc != null && !ReferenceEquals(nc, cond))
						{
							join.JoinedTable.Condition.Conditions.Add(nc);
							subQuery.Where.SearchCondition.Conditions.RemoveAt(j);
							j--;
						}
					}

					if (!query.GroupBy.IsEmpty/* && subQuery.Select.Columns.Count > 1*/)
					{
						var oldFunc = (SqlFunction)subQuery.Select.Columns[0].Expression;

						subQuery.Select.Columns.RemoveAt(0);

						query.Select.Columns[i].Expression =
							new SqlFunction(oldFunc.SystemType, oldFunc.Name, subQuery.Select.Columns[0]);
					}
					else
					{
						query.Select.Columns[i].Expression = subQuery.Select.Columns[0];
					}
				}
			}
		}
Esempio n. 9
0
		SelectQuery MoveSubQueryColumn(SelectQuery selectQuery)
		{
			var dic = new Dictionary<IQueryElement,IQueryElement>();

			new QueryVisitor().Visit(selectQuery, element =>
			{
				if (element.ElementType != QueryElementType.SqlQuery)
					return;

				var query = (SelectQuery)element;

				for (var i = 0; i < query.Select.Columns.Count; i++)
				{
					var col = query.Select.Columns[i];

					if (col.Expression.ElementType == QueryElementType.SqlQuery)
					{
						var subQuery    = (SelectQuery)col.Expression;
						var allTables   = new HashSet<ISqlTableSource>();
						var levelTables = new HashSet<ISqlTableSource>();

						bool CheckTable(IQueryElement e)
						{
							switch (e.ElementType)
							{
								case QueryElementType.SqlField : return !allTables.Contains(((SqlField) e).Table);
								case QueryElementType.Column   : return !allTables.Contains(((SqlColumn)e).Parent);
							}

							return false;
						}

						new QueryVisitor().Visit(subQuery, e =>
						{
							if (e is ISqlTableSource source)
								allTables.Add(source);
						});

						new QueryVisitor().Visit(subQuery, e =>
						{
							if (e is ISqlTableSource source && subQuery.From.IsChild(source))
								levelTables.Add(source);
						});

						if (SqlProviderFlags.IsSubQueryColumnSupported && QueryVisitor.Find(subQuery, CheckTable) == null)
							continue;

						// Join should not have ParentSelect, while SubQuery has
						subQuery.ParentSelect = null;

						var join = subQuery.LeftJoin();

						query.From.Tables[0].Joins.Add(join.JoinedTable);

						SelectQueryOptimizer.OptimizeSearchCondition(subQuery.Where.SearchCondition);

						var isCount      = false;
						var isAggregated = false;

						if (subQuery.Select.Columns.Count == 1)
						{
							var subCol = subQuery.Select.Columns[0];

							if (subCol.Expression.ElementType == QueryElementType.SqlFunction)
							{
								switch (((SqlFunction)subCol.Expression).Name)
								{
									case "Count" : isCount = true; break;
								}

								isAggregated = ((SqlFunction) subCol.Expression).IsAggregate;
							}
						}

						if (SqlProviderFlags.IsSubQueryColumnSupported && !isCount)
							continue;

						var allAnd = true;

						for (var j = 0; allAnd && j < subQuery.Where.SearchCondition.Conditions.Count - 1; j++)
						{
							var cond = subQuery.Where.SearchCondition.Conditions[j];

							if (cond.IsOr)
								allAnd = false;
						}

						if (!allAnd)
							continue;

						var modified = false;

						for (var j = 0; j < subQuery.Where.SearchCondition.Conditions.Count; j++)
						{
							var cond = subQuery.Where.SearchCondition.Conditions[j];

							if (QueryVisitor.Find(cond, CheckTable) == null)
								continue;

							var replaced = new Dictionary<IQueryElement,IQueryElement>();

							var nc = new QueryVisitor().Convert(cond, e =>
							{
								var ne = e;

								switch (e.ElementType)
								{
									case QueryElementType.SqlField :
										if (replaced.TryGetValue(e, out ne))
											return ne;

										if (levelTables.Contains(((SqlField)e).Table))
										{
											if (isAggregated)
												subQuery.GroupBy.Expr((SqlField)e);
											ne = subQuery.Select.Columns[subQuery.Select.Add((SqlField)e)];
										}

										break;

									case QueryElementType.Column   :
										if (replaced.TryGetValue(e, out ne))
											return ne;

										if (levelTables.Contains(((SqlColumn)e).Parent))
										{
											if (isAggregated)
												subQuery.GroupBy.Expr((SqlColumn)e);
											ne = subQuery.Select.Columns[subQuery.Select.Add((SqlColumn)e)];
										}

										break;
								}

								if (!ReferenceEquals(e, ne))
									replaced.Add(e, ne);

								return ne;
							});

							if (nc != null && !ReferenceEquals(nc, cond))
							{
								modified = true;

								join.JoinedTable.Condition.Conditions.Add(nc);
								subQuery.Where.SearchCondition.Conditions.RemoveAt(j);
								j--;
							}
						}

						if (modified || isAggregated)
						{
							SqlColumn newColumn;
							if (isCount && !query.GroupBy.IsEmpty)
							{
								var oldFunc = (SqlFunction)subQuery.Select.Columns[0].Expression;

								subQuery.Select.Columns.RemoveAt(0);

								newColumn = new SqlColumn(
									query,
									new SqlFunction(oldFunc.SystemType, oldFunc.Name, subQuery.Select.Columns[0]));
							}
							else if (isAggregated && !query.GroupBy.IsEmpty)
							{
								var oldFunc = (SqlFunction)subQuery.Select.Columns[0].Expression;

								subQuery.Select.Columns.RemoveAt(0);

								var idx = subQuery.Select.Add(oldFunc.Parameters[0]);

								newColumn = new SqlColumn(
									query,
									new SqlFunction(oldFunc.SystemType, oldFunc.Name, subQuery.Select.Columns[idx]));
							}
							else
							{
								newColumn = new SqlColumn(query, subQuery.Select.Columns[0]);
							}

							dic.Add(col, newColumn);
						}
					}
Esempio n. 10
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            var wrapped = false;

            if (sequence.SelectQuery.Select.TakeValue != null ||
                sequence.SelectQuery.Select.SkipValue != null)
            {
                sequence = new SubQueryContext(sequence);
                wrapped  = true;
            }

            var lambda = (LambdaExpression)methodCall.Arguments[1].Unwrap();

            SqlInfo[] sql;

            while (true)
            {
                var sparent = sequence.Parent;
                var order   = new ExpressionContext(buildInfo.Parent, sequence, lambda);
                var body    = lambda.Body.Unwrap();
                sql = builder.ConvertExpressions(order, body, ConvertFlags.Key);

                builder.ReplaceParent(order, sparent);

                if (wrapped)
                {
                    break;
                }

                // handle situation when order by uses complex field

                var isComplex = false;
                foreach (var sqlInfo in sql)
                {
                    // possible we have to extend this list
                    isComplex = null != QueryVisitor.Find(sqlInfo.Sql,
                                                          e => e.ElementType == QueryElementType.SqlQuery);
                    if (isComplex)
                    {
                        break;
                    }
                }

                if (!isComplex)
                {
                    break;
                }

                sequence = new SubQueryContext(sequence);
                wrapped  = true;
            }


            if (!methodCall.Method.Name.StartsWith("Then") && !Configuration.Linq.DoNotClearOrderBys)
            {
                sequence.SelectQuery.OrderBy.Items.Clear();
            }

            foreach (var expr in sql)
            {
                var e = builder.ConvertSearchCondition(sequence, expr.Sql);
                sequence.SelectQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending"));
            }

            return(sequence);
        }