Mercurial > pub > bltoolkit
view Source/Data/Linq/Builder/SubQueryContext.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line source
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace BLToolkit.Data.Linq.Builder { using BLToolkit.Linq; using Data.Sql; class SubQueryContext : PassThroughContext { public readonly IBuildContext SubQuery; public SubQueryContext(IBuildContext subQuery, SqlQuery sqlQuery, bool addToSql) : base(subQuery) { if (sqlQuery == subQuery.SqlQuery) throw new ArgumentException("Wrong subQuery argument.", "subQuery"); SubQuery = subQuery; SubQuery.Parent = this; SqlQuery = sqlQuery; if (addToSql) sqlQuery.From.Table(SubQuery.SqlQuery); } public SubQueryContext(IBuildContext subQuery, bool addToSql) : this(subQuery, new SqlQuery { ParentSql = subQuery.SqlQuery.ParentSql }, addToSql) { } public SubQueryContext(IBuildContext subQuery) : this(subQuery, true) { } public override SqlQuery SqlQuery { get; set; } public override IBuildContext Parent { get; set; } public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter) { if (Expression.NodeType == ExpressionType.Lambda) { var le = (LambdaExpression)Expression; if (le.Parameters.Count == 1 && null != Expression.Find( e => e.NodeType == ExpressionType.Call && ((MethodCallExpression)e).IsQueryable())) { if (le.Body.NodeType == ExpressionType.New) { var ne = (NewExpression)le.Body; var p = Expression.Parameter(ne.Type, "p"); var seq = new SelectContext( Parent, Expression.Lambda( Expression.New( ne.Constructor, ne.Members.Select(m => Expression.MakeMemberAccess(p, m)).ToArray(), ne.Members), p), this); seq.BuildQuery(query, queryParameter); return; } if (le.Body.NodeType == ExpressionType.MemberInit) { var mi = (MemberInitExpression)le.Body; if (mi.NewExpression.Arguments.Count == 0 && mi.Bindings.All(b => b is MemberAssignment)) { var p = Expression.Parameter(mi.Type, "p"); var seq = new SelectContext( Parent, Expression.Lambda( Expression.MemberInit( mi.NewExpression, mi.Bindings .OfType<MemberAssignment>() .Select(ma => Expression.Bind(ma.Member, Expression.MakeMemberAccess(p, ma.Member))) .ToArray()), p), this); seq.BuildQuery(query, queryParameter); return; } } } } base.BuildQuery(query, queryParameter); } public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) { return SubQuery .ConvertToIndex(expression, level, flags) .Select(idx => new SqlInfo(idx.Members) { Sql = SubQuery.SqlQuery.Select.Columns[idx.Index] }) .ToArray(); } // JoinContext has similar logic. Consider to review it. // public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) { return ConvertToSql(expression, level, flags) .Select(idx => { idx.Query = SqlQuery; idx.Index = GetIndex((SqlQuery.Column)idx.Sql); return idx; }) .ToArray(); } public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor testFlag) { switch (testFlag) { case RequestFor.SubQuery : return IsExpressionResult.True; } return base.IsExpression(expression, level, testFlag); } internal protected readonly Dictionary<ISqlExpression,int> ColumnIndexes = new Dictionary<ISqlExpression,int>(); protected virtual int GetIndex(SqlQuery.Column column) { int idx; if (!ColumnIndexes.TryGetValue(column, out idx)) { idx = SqlQuery.Select.Add(column); ColumnIndexes.Add(column, idx); } return idx; } public override int ConvertToParentIndex(int index, IBuildContext context) { var idx = GetIndex(context.SqlQuery.Select.Columns[index]); return Parent == null ? idx : Parent.ConvertToParentIndex(idx, this); } public override void SetAlias(string alias) { if (alias.Contains('<')) return; if (SqlQuery.From.Tables[0].Alias == null) SqlQuery.From.Tables[0].Alias = alias; } public override ISqlExpression GetSubQuery(IBuildContext context) { return null; } } }