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