@@ -9,6 +9,7 @@ namespace SubSonic.Builders
99 using Collections ;
1010 using Linq ;
1111 using Linq . Expressions ;
12+ using System . Diagnostics ;
1213
1314 public partial class DbWherePredicateBuilder
1415 {
@@ -197,16 +198,32 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
197198 {
198199 Expression root = null ;
199200
201+ bool shouldBuildSqlMapping = false ;
202+
200203 if ( call . Object is MemberExpression member )
201204 {
202- if ( member . Expression . IsNotNull ( ) )
205+ shouldBuildSqlMapping = member . Expression is ParameterExpression ;
206+
207+ if ( member . Member is FieldInfo field &&
208+ member . Expression is ConstantExpression fieldValue )
203209 {
204- root = Visit ( member ) ;
210+ root = CheckValueAgainstType ( member . Type , field . GetValue ( fieldValue . Value ) ) ;
211+ }
212+ else if ( member . Member is PropertyInfo staticProperty &&
213+ member . Expression is null )
214+ { // this use case the property is most likely static
215+ Debug . Assert ( staticProperty . GetMethod . IsStatic ) ;
216+
217+ root = CheckValueAgainstType ( member . Type , staticProperty . GetValue ( null ) ) ;
205218 }
206219 else if ( member . Member is PropertyInfo property &&
207- property . GetMethod . IsStatic )
220+ member . Expression is ConstantExpression propertyValue )
208221 {
209- root = Expression . Constant ( property . GetValue ( null ) ) ;
222+ root = CheckValueAgainstType ( member . Type , property . GetValue ( propertyValue . Value ) ) ;
223+ }
224+ else if ( member . Expression is ParameterExpression parameter )
225+ {
226+ root = Visit ( member ) ;
210227 }
211228 }
212229
@@ -224,13 +241,37 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
224241 }
225242 }
226243
227- if ( root is ConstantExpression constant )
244+ if ( ! shouldBuildSqlMapping )
228245 {
229- return GetNamedExpression ( call . Method . Invoke ( constant . Value , GetArrayOfValues ( arguments ) ) ) ;
246+ if ( root is ConstantExpression constant )
247+ {
248+ return Expression . Constant ( call . Method . Invoke ( constant . Value , GetArrayOfValues ( arguments ) ) ) ;
249+ }
250+ else if ( root is NewExpression @new )
251+ {
252+ object value = null ;
253+
254+ if ( @new . Type . IsNullableType ( ) )
255+ {
256+ Debug . Assert ( @new . Arguments . Count == arguments . Count ) ;
257+
258+ value = @new . Constructor . Invoke ( GetArrayOfValues ( arguments ) ) ;
259+ }
260+ else
261+ {
262+ value = @new . Constructor . Invoke ( GetArrayOfValues ( @new . Arguments ) ) ;
263+ }
264+
265+ return GetNamedExpression ( call . Method . Invoke ( value , GetArrayOfValues ( arguments ) ) ) ;
266+ }
267+ }
268+ else if ( root is ConstantExpression constant )
269+ {
270+ return GetNamedExpression ( call . Method . Invoke ( constant . Value , GetArrayOfValues ( arguments ) ) ) ;
230271 }
231272 else
232273 {
233- return Expression . Call ( root , call . Method , arguments ) ;
274+ return Expression . Call ( root , call . Method , GetArrayOfNamedValues ( arguments ) ) ;
234275 }
235276 }
236277
@@ -242,16 +283,57 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
242283 return base . VisitMethodCall ( node ) ;
243284 }
244285
286+ private Expression CheckValueAgainstType ( Type type , object value )
287+ {
288+ if ( type . IsNullableType ( ) )
289+ {
290+ if ( value is null )
291+ {
292+ return Expression . New ( type . GetConstructor ( type . GenericTypeArguments ) , type . GenericTypeArguments . Select ( x => Expression . Constant ( Activator . CreateInstance ( x ) , x ) ) ) ;
293+ }
294+ else
295+ {
296+ return Expression . New ( type . GetConstructor ( type . GenericTypeArguments ) , Expression . Constant ( value ) ) ;
297+ }
298+ }
299+ else if ( value != null &&
300+ value . GetType ( ) == type )
301+ {
302+ return Expression . Constant ( value ) ;
303+ }
304+
305+ throw Error . NotSupported ( ) ;
306+ }
307+
308+ private Expression [ ] GetArrayOfNamedValues ( IEnumerable < Expression > arguments ) => arguments . Select ( x =>
309+ {
310+ if ( x is DbNamedValueExpression existing )
311+ {
312+ return existing ;
313+ }
314+ else if ( x is ConstantExpression constant )
315+ {
316+ return GetNamedExpression ( constant . Value ) ;
317+ }
318+
319+ throw Error . NotSupported ( ) ;
320+ } ) . ToArray ( ) ;
321+
245322 private object [ ] GetArrayOfValues ( IEnumerable < Expression > expressions ) => expressions . Select ( x =>
246323 {
247324 if ( x is ConstantExpression constant )
248325 {
249326 return constant . Value ;
250327 }
251- else
328+ else if ( x is DbNamedValueExpression named )
252329 {
253- throw Error . NotImplemented ( ) ;
330+ if ( named . Value is ConstantExpression namedConstant )
331+ {
332+ return namedConstant . Value ;
333+ }
254334 }
335+
336+ throw Error . NotSupported ( ) ;
255337 } ) . ToArray ( ) ;
256338
257339 [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Reliability" , "CA2000:Dispose objects before losing scope" , Justification = "this data table is cleaned up after the result is back from the db." ) ]
0 commit comments