@@ -135,49 +135,72 @@ protected override Expression VisitConstant(ConstantExpression expression)
135
135
{
136
136
if ( ! _parameters . ContainsKey ( expression ) && ! typeof ( IQueryable ) . IsAssignableFrom ( expression . Type ) && ! IsNullObject ( expression ) )
137
137
{
138
- // We use null for the type to indicate that the caller should let HQL figure it out.
139
- object value = expression . Value ;
140
- IType type = null ;
141
-
142
- // We have a bit more information about the null parameter value.
143
- // Figure out a type so that HQL doesn't break on the null. (Related to NH-2430)
144
- // In v5.3 types are calculated by ParameterTypeLocator, this logic is only for back compatibility.
145
- // TODO 6.0: Remove
146
- if ( expression . Value == null )
147
- type = NHibernateUtil . GuessType ( expression . Type ) ;
148
-
149
- // Constant characters should be sent as strings
150
- // TODO 6.0: Remove
151
- if ( _queryVariables == null && expression . Type == typeof ( char ) )
152
- {
153
- value = value . ToString ( ) ;
154
- }
155
-
156
- // There is more information available in the Linq expression than to HQL directly.
157
- // In some cases it might be advantageous to use the extra info. Assuming this
158
- // comes up, it would be nice to combine the HQL parameter type determination code
159
- // and the Expression information.
160
-
161
- NamedParameter parameter = null ;
162
- if ( _queryVariables != null &&
163
- _queryVariables . TryGetValue ( expression , out var variable ) &&
164
- ! _variableParameters . TryGetValue ( variable , out parameter ) )
165
- {
166
- parameter = CreateParameter ( expression , value , type ) ;
167
- _variableParameters . Add ( variable , parameter ) ;
168
- }
138
+ AddConstantExpressionParameter ( expression , null ) ;
139
+ }
169
140
170
- if ( parameter == null )
171
- {
172
- parameter = CreateParameter ( expression , value , type ) ;
173
- }
141
+ return base . VisitConstant ( expression ) ;
142
+ }
174
143
175
- _parameters . Add ( expression , parameter ) ;
144
+ protected override Expression VisitUnary ( UnaryExpression node )
145
+ {
146
+ // If we have an expression like "Convert(<constant>)" we do not want to lose the conversion operation
147
+ // because it might be necessary if the types are incompatible with each other, which might happen if
148
+ // the expression uses an implicitly or explicitly defined cast operator.
149
+ if ( node . NodeType == ExpressionType . Convert &&
150
+ node . Method != null && // The implicit/explicit operator method
151
+ node . Operand is ConstantExpression constantExpression )
152
+ {
153
+ // Instead of getting constantExpression.Value, we override the value by compiling and executing this subtree,
154
+ // performing the cast.
155
+ var lambda = Expression . Lambda < Func < object > > ( Expression . Convert ( node , typeof ( object ) ) ) ;
156
+ var compiledLambda = lambda . Compile ( ) ;
176
157
177
- return base . VisitConstant ( expression ) ;
158
+ AddConstantExpressionParameter ( constantExpression , compiledLambda ( ) ) ;
178
159
}
179
160
180
- return base . VisitConstant ( expression ) ;
161
+ return base . VisitUnary ( node ) ;
162
+ }
163
+
164
+ private void AddConstantExpressionParameter ( ConstantExpression expression , object overrideValue )
165
+ {
166
+ // We use null for the type to indicate that the caller should let HQL figure it out.
167
+ object value = overrideValue ?? expression . Value ;
168
+ IType type = null ;
169
+
170
+ // We have a bit more information about the null parameter value.
171
+ // Figure out a type so that HQL doesn't break on the null. (Related to NH-2430)
172
+ // In v5.3 types are calculated by ParameterTypeLocator, this logic is only for back compatibility.
173
+ // TODO 6.0: Remove
174
+ if ( value == null )
175
+ type = NHibernateUtil . GuessType ( expression . Type ) ;
176
+
177
+ // Constant characters should be sent as strings
178
+ // TODO 6.0: Remove
179
+ if ( _queryVariables == null && expression . Type == typeof ( char ) )
180
+ {
181
+ value = value . ToString ( ) ;
182
+ }
183
+
184
+ // There is more information available in the Linq expression than to HQL directly.
185
+ // In some cases it might be advantageous to use the extra info. Assuming this
186
+ // comes up, it would be nice to combine the HQL parameter type determination code
187
+ // and the Expression information.
188
+
189
+ NamedParameter parameter = null ;
190
+ if ( _queryVariables != null &&
191
+ _queryVariables . TryGetValue ( expression , out var variable ) &&
192
+ ! _variableParameters . TryGetValue ( variable , out parameter ) )
193
+ {
194
+ parameter = CreateParameter ( expression , value , type ) ;
195
+ _variableParameters . Add ( variable , parameter ) ;
196
+ }
197
+
198
+ if ( parameter == null )
199
+ {
200
+ parameter = CreateParameter ( expression , value , type ) ;
201
+ }
202
+
203
+ _parameters . Add ( expression , parameter ) ;
181
204
}
182
205
183
206
private NamedParameter CreateParameter ( ConstantExpression expression , object value , IType type )
0 commit comments