0
|
1 using System;
|
|
2 using System.Linq;
|
|
3 using System.Linq.Expressions;
|
|
4
|
|
5 namespace BLToolkit.Data.Linq.Builder
|
|
6 {
|
|
7 using BLToolkit.Linq;
|
|
8 using Data.Sql;
|
|
9
|
|
10 class DefaultIfEmptyBuilder : MethodCallBuilder
|
|
11 {
|
|
12 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
|
|
13 {
|
|
14 return methodCall.IsQueryable("DefaultIfEmpty");
|
|
15 }
|
|
16
|
|
17 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
|
|
18 {
|
|
19 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
|
|
20 var defaultValue = methodCall.Arguments.Count == 1 ? null : methodCall.Arguments[1].Unwrap();
|
|
21
|
|
22 if (buildInfo.Parent is SelectManyBuilder.SelectManyContext)
|
|
23 {
|
|
24 var groupJoin = ((SelectManyBuilder.SelectManyContext)buildInfo.Parent).Sequence[0] as JoinBuilder.GroupJoinContext;
|
|
25
|
|
26 if (groupJoin != null)
|
|
27 {
|
|
28 groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Left;
|
|
29 groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak = false;
|
|
30 }
|
|
31 }
|
|
32
|
|
33 return new DefaultIfEmptyContext(buildInfo.Parent, sequence, defaultValue);
|
|
34 }
|
|
35
|
|
36 protected override SequenceConvertInfo Convert(
|
|
37 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
|
|
38 {
|
|
39 return null;
|
|
40 }
|
|
41
|
|
42 public class DefaultIfEmptyContext : SequenceContextBase
|
|
43 {
|
|
44 public DefaultIfEmptyContext(IBuildContext parent, IBuildContext sequence, Expression defaultValue)
|
|
45 : base(parent, sequence, null)
|
|
46 {
|
|
47 _defaultValue = defaultValue;
|
|
48 }
|
|
49
|
|
50 private readonly Expression _defaultValue;
|
|
51
|
|
52 public override Expression BuildExpression(Expression expression, int level)
|
|
53 {
|
|
54 var expr = Sequence.BuildExpression(expression, level);
|
|
55
|
|
56 if (expression == null)
|
|
57 {
|
|
58 var q =
|
|
59 from col in SqlQuery.Select.Columns
|
|
60 where !col.CanBeNull()
|
|
61 select SqlQuery.Select.Columns.IndexOf(col);
|
|
62
|
|
63 var idx = q.DefaultIfEmpty(-1).First();
|
|
64
|
|
65 if (idx == -1)
|
|
66 idx = SqlQuery.Select.Add(new SqlValue((int?) 1));
|
|
67
|
|
68 var n = ConvertToParentIndex(idx, this);
|
|
69
|
|
70 var e = Expression.Call(
|
|
71 ExpressionBuilder.DataReaderParam,
|
|
72 ReflectionHelper.DataReader.IsDBNull,
|
|
73 Expression.Constant(n)) as Expression;
|
|
74
|
|
75 var defaultValue = _defaultValue ?? Expression.Constant(null, expr.Type);
|
|
76
|
|
77 #if FW4 || SILVERLIGHT
|
|
78
|
|
79 if (expr.NodeType == ExpressionType.Parameter)
|
|
80 {
|
|
81 var par = (ParameterExpression)expr;
|
|
82 var pidx = Builder.BlockVariables.IndexOf(par);
|
|
83
|
|
84 if (pidx >= 0)
|
|
85 {
|
|
86 var ex = Builder.BlockExpressions[pidx];
|
|
87
|
|
88 if (ex.NodeType == ExpressionType.Assign)
|
|
89 {
|
|
90 var bex = (BinaryExpression)ex;
|
|
91
|
|
92 if (bex.Left == expr)
|
|
93 {
|
|
94 if (bex.Right.NodeType != ExpressionType.Conditional)
|
|
95 {
|
|
96 Builder.BlockExpressions[pidx] =
|
|
97 Expression.Assign(
|
|
98 bex.Left,
|
|
99 Expression.Condition(e, defaultValue, bex.Right));
|
|
100 }
|
|
101 }
|
|
102 }
|
|
103 }
|
|
104 }
|
|
105
|
|
106 #endif
|
|
107
|
|
108 expr = Expression.Condition(e, defaultValue, expr);
|
|
109 }
|
|
110
|
|
111 return expr;
|
|
112 }
|
|
113
|
|
114 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
|
|
115 {
|
|
116 return Sequence.ConvertToSql(expression, level, flags);
|
|
117 }
|
|
118
|
|
119 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
|
|
120 {
|
|
121 return Sequence.ConvertToIndex(expression, level, flags);
|
|
122 }
|
|
123
|
|
124 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag)
|
|
125 {
|
|
126 return Sequence.IsExpression(expression, level, requestFlag);
|
|
127 }
|
|
128
|
|
129 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo)
|
|
130 {
|
|
131 return Sequence.GetContext(expression, level, buildInfo);
|
|
132 }
|
|
133 }
|
|
134 }
|
|
135 }
|