Mercurial > pub > bltoolkit
diff Source/Data/Linq/Builder/DefaultIfEmptyBuilder.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Data/Linq/Builder/DefaultIfEmptyBuilder.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,135 @@ +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace BLToolkit.Data.Linq.Builder +{ + using BLToolkit.Linq; + using Data.Sql; + + class DefaultIfEmptyBuilder : MethodCallBuilder + { + protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) + { + return methodCall.IsQueryable("DefaultIfEmpty"); + } + + protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) + { + var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); + var defaultValue = methodCall.Arguments.Count == 1 ? null : methodCall.Arguments[1].Unwrap(); + + if (buildInfo.Parent is SelectManyBuilder.SelectManyContext) + { + var groupJoin = ((SelectManyBuilder.SelectManyContext)buildInfo.Parent).Sequence[0] as JoinBuilder.GroupJoinContext; + + if (groupJoin != null) + { + groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Left; + groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak = false; + } + } + + return new DefaultIfEmptyContext(buildInfo.Parent, sequence, defaultValue); + } + + protected override SequenceConvertInfo Convert( + ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param) + { + return null; + } + + public class DefaultIfEmptyContext : SequenceContextBase + { + public DefaultIfEmptyContext(IBuildContext parent, IBuildContext sequence, Expression defaultValue) + : base(parent, sequence, null) + { + _defaultValue = defaultValue; + } + + private readonly Expression _defaultValue; + + public override Expression BuildExpression(Expression expression, int level) + { + var expr = Sequence.BuildExpression(expression, level); + + if (expression == null) + { + var q = + from col in SqlQuery.Select.Columns + where !col.CanBeNull() + select SqlQuery.Select.Columns.IndexOf(col); + + var idx = q.DefaultIfEmpty(-1).First(); + + if (idx == -1) + idx = SqlQuery.Select.Add(new SqlValue((int?) 1)); + + var n = ConvertToParentIndex(idx, this); + + var e = Expression.Call( + ExpressionBuilder.DataReaderParam, + ReflectionHelper.DataReader.IsDBNull, + Expression.Constant(n)) as Expression; + + var defaultValue = _defaultValue ?? Expression.Constant(null, expr.Type); + +#if FW4 || SILVERLIGHT + + if (expr.NodeType == ExpressionType.Parameter) + { + var par = (ParameterExpression)expr; + var pidx = Builder.BlockVariables.IndexOf(par); + + if (pidx >= 0) + { + var ex = Builder.BlockExpressions[pidx]; + + if (ex.NodeType == ExpressionType.Assign) + { + var bex = (BinaryExpression)ex; + + if (bex.Left == expr) + { + if (bex.Right.NodeType != ExpressionType.Conditional) + { + Builder.BlockExpressions[pidx] = + Expression.Assign( + bex.Left, + Expression.Condition(e, defaultValue, bex.Right)); + } + } + } + } + } + +#endif + + expr = Expression.Condition(e, defaultValue, expr); + } + + return expr; + } + + public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) + { + return Sequence.ConvertToSql(expression, level, flags); + } + + public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) + { + return Sequence.ConvertToIndex(expression, level, flags); + } + + public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag) + { + return Sequence.IsExpression(expression, level, requestFlag); + } + + public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo) + { + return Sequence.GetContext(expression, level, buildInfo); + } + } + } +}