2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
- using System . Collections ;
6
5
using System . Collections . Generic ;
7
6
using System . Data . Common ;
8
7
using System . Linq . Expressions ;
@@ -38,17 +37,19 @@ public virtual (SelectExpression selectExpression, bool canCache) Optimize(
38
37
SelectExpression selectExpression , IReadOnlyDictionary < string , object > parametersValues )
39
38
{
40
39
var canCache = true ;
40
+ var nullSemanticsRewritingExpressionVisitor = new NullSemanticsRewritingExpressionVisitor (
41
+ UseRelationalNulls ,
42
+ Dependencies . SqlExpressionFactory ,
43
+ parametersValues ) ;
41
44
42
- var inExpressionOptimized = new InExpressionValuesExpandingExpressionVisitor (
43
- Dependencies . SqlExpressionFactory , parametersValues ) . Visit ( selectExpression ) ;
44
-
45
- if ( ! ReferenceEquals ( selectExpression , inExpressionOptimized ) )
45
+ var nullSemanticsOptimized = nullSemanticsRewritingExpressionVisitor . Visit ( selectExpression ) ;
46
+ if ( ! nullSemanticsRewritingExpressionVisitor . CanCache )
46
47
{
47
48
canCache = false ;
48
49
}
49
50
50
- var nullParametersOptimized = new ParameterNullabilityBasedSqlExpressionOptimizingExpressionVisitor (
51
- Dependencies . SqlExpressionFactory , UseRelationalNulls , parametersValues ) . Visit ( inExpressionOptimized ) ;
51
+ var nullParametersOptimized = new SqlExpressionOptimizingExpressionVisitor (
52
+ Dependencies . SqlExpressionFactory , UseRelationalNulls , parametersValues ) . Visit ( nullSemanticsOptimized ) ;
52
53
53
54
var fromSqlParameterOptimized = new FromSqlParameterApplyingExpressionVisitor (
54
55
Dependencies . SqlExpressionFactory ,
@@ -63,163 +64,6 @@ public virtual (SelectExpression selectExpression, bool canCache) Optimize(
63
64
return ( selectExpression : ( SelectExpression ) fromSqlParameterOptimized , canCache ) ;
64
65
}
65
66
66
- private sealed class ParameterNullabilityBasedSqlExpressionOptimizingExpressionVisitor : SqlExpressionOptimizingExpressionVisitor
67
- {
68
- private readonly IReadOnlyDictionary < string , object > _parametersValues ;
69
-
70
- public ParameterNullabilityBasedSqlExpressionOptimizingExpressionVisitor (
71
- ISqlExpressionFactory sqlExpressionFactory ,
72
- bool useRelationalNulls ,
73
- IReadOnlyDictionary < string , object > parametersValues )
74
- : base ( sqlExpressionFactory , useRelationalNulls )
75
- {
76
- _parametersValues = parametersValues ;
77
- }
78
-
79
- protected override Expression VisitSqlUnaryExpression ( SqlUnaryExpression sqlUnaryExpression )
80
- {
81
- var result = base . VisitSqlUnaryExpression ( sqlUnaryExpression ) ;
82
- if ( result is SqlUnaryExpression newUnaryExpression
83
- && newUnaryExpression . Operand is SqlParameterExpression parameterOperand )
84
- {
85
- var parameterValue = _parametersValues [ parameterOperand . Name ] ;
86
- if ( sqlUnaryExpression . OperatorType == ExpressionType . Equal )
87
- {
88
- return SqlExpressionFactory . Constant ( parameterValue == null , sqlUnaryExpression . TypeMapping ) ;
89
- }
90
-
91
- if ( sqlUnaryExpression . OperatorType == ExpressionType . NotEqual )
92
- {
93
- return SqlExpressionFactory . Constant ( parameterValue != null , sqlUnaryExpression . TypeMapping ) ;
94
- }
95
- }
96
-
97
- return result ;
98
- }
99
-
100
- protected override Expression VisitSqlBinaryExpression ( SqlBinaryExpression sqlBinaryExpression )
101
- {
102
- var result = base . VisitSqlBinaryExpression ( sqlBinaryExpression ) ;
103
- if ( result is SqlBinaryExpression sqlBinaryResult )
104
- {
105
- var leftNullParameter = sqlBinaryResult . Left is SqlParameterExpression leftParameter
106
- && _parametersValues [ leftParameter . Name ] == null ;
107
-
108
- var rightNullParameter = sqlBinaryResult . Right is SqlParameterExpression rightParameter
109
- && _parametersValues [ rightParameter . Name ] == null ;
110
-
111
- if ( ( sqlBinaryResult . OperatorType == ExpressionType . Equal || sqlBinaryResult . OperatorType == ExpressionType . NotEqual )
112
- && ( leftNullParameter || rightNullParameter ) )
113
- {
114
- return SimplifyNullComparisonExpression (
115
- sqlBinaryResult . OperatorType ,
116
- sqlBinaryResult . Left ,
117
- sqlBinaryResult . Right ,
118
- leftNullParameter ,
119
- rightNullParameter ,
120
- sqlBinaryResult . TypeMapping ) ;
121
- }
122
- }
123
-
124
- return result ;
125
- }
126
- }
127
-
128
- private sealed class InExpressionValuesExpandingExpressionVisitor : ExpressionVisitor
129
- {
130
- private readonly ISqlExpressionFactory _sqlExpressionFactory ;
131
- private readonly IReadOnlyDictionary < string , object > _parametersValues ;
132
-
133
- public InExpressionValuesExpandingExpressionVisitor (
134
- ISqlExpressionFactory sqlExpressionFactory , IReadOnlyDictionary < string , object > parametersValues )
135
- {
136
- _sqlExpressionFactory = sqlExpressionFactory ;
137
- _parametersValues = parametersValues ;
138
- }
139
-
140
- public override Expression Visit ( Expression expression )
141
- {
142
- if ( expression is InExpression inExpression
143
- && inExpression . Values != null )
144
- {
145
- var inValues = new List < object > ( ) ;
146
- var hasNullValue = false ;
147
- RelationalTypeMapping typeMapping = null ;
148
-
149
- switch ( inExpression . Values )
150
- {
151
- case SqlConstantExpression sqlConstant :
152
- {
153
- typeMapping = sqlConstant . TypeMapping ;
154
- var values = ( IEnumerable ) sqlConstant . Value ;
155
- foreach ( var value in values )
156
- {
157
- if ( value == null )
158
- {
159
- hasNullValue = true ;
160
- continue ;
161
- }
162
-
163
- inValues . Add ( value ) ;
164
- }
165
-
166
- break ;
167
- }
168
-
169
- case SqlParameterExpression sqlParameter :
170
- {
171
- typeMapping = sqlParameter . TypeMapping ;
172
- var values = ( IEnumerable ) _parametersValues [ sqlParameter . Name ] ;
173
- foreach ( var value in values )
174
- {
175
- if ( value == null )
176
- {
177
- hasNullValue = true ;
178
- continue ;
179
- }
180
-
181
- inValues . Add ( value ) ;
182
- }
183
-
184
- break ;
185
- }
186
- }
187
-
188
- var updatedInExpression = inValues . Count > 0
189
- ? _sqlExpressionFactory . In (
190
- ( SqlExpression ) Visit ( inExpression . Item ) ,
191
- _sqlExpressionFactory . Constant ( inValues , typeMapping ) ,
192
- inExpression . IsNegated )
193
- : null ;
194
-
195
- var nullCheckExpression = hasNullValue
196
- ? inExpression . IsNegated
197
- ? _sqlExpressionFactory . IsNotNull ( inExpression . Item )
198
- : _sqlExpressionFactory . IsNull ( inExpression . Item )
199
- : null ;
200
-
201
- if ( updatedInExpression != null
202
- && nullCheckExpression != null )
203
- {
204
- return inExpression . IsNegated
205
- ? _sqlExpressionFactory . AndAlso ( updatedInExpression , nullCheckExpression )
206
- : _sqlExpressionFactory . OrElse ( updatedInExpression , nullCheckExpression ) ;
207
- }
208
-
209
- if ( updatedInExpression == null
210
- && nullCheckExpression == null )
211
- {
212
- return _sqlExpressionFactory . Equal (
213
- _sqlExpressionFactory . Constant ( true ) , _sqlExpressionFactory . Constant ( inExpression . IsNegated ) ) ;
214
- }
215
-
216
- return ( SqlExpression ) updatedInExpression ?? nullCheckExpression ;
217
- }
218
-
219
- return base . Visit ( expression ) ;
220
- }
221
- }
222
-
223
67
private sealed class FromSqlParameterApplyingExpressionVisitor : ExpressionVisitor
224
68
{
225
69
private readonly IDictionary < FromSqlExpression , Expression > _visitedFromSqlExpressions
0 commit comments