1- using AutoMapper ;
2- using AutoMapper . Internal ;
3- using AutoMapper . QueryableExtensions ;
4- using Microsoft . EntityFrameworkCore ;
5- using Microsoft . EntityFrameworkCore . Infrastructure ;
6- using Swashbuckle . AspNetCore . SwaggerGen ;
1+ using System . ComponentModel . DataAnnotations ;
72using System . Globalization ;
83using System . Linq . Expressions ;
94using System . Reflection ;
105using System . Reflection . Emit ;
116using System . Text . Json ;
127using System . Text . Json . Nodes ;
138using System . Text . Json . Serialization ;
9+ using AutoMapper ;
10+ using AutoMapper . Internal ;
11+ using AutoMapper . QueryableExtensions ;
12+ using Microsoft . EntityFrameworkCore ;
13+ using Microsoft . EntityFrameworkCore . Infrastructure ;
14+ using Swashbuckle . AspNetCore . SwaggerGen ;
1415
1516namespace Infragistics . QueryBuilder . Executor
1617{
@@ -33,6 +34,20 @@ public static object[] Run<TSource, TTarget>(this IQueryable<TSource> source, Qu
3334 return db is not null ? BuildQuery < TSource , TTarget > ( db , source , query , mapper ) . ToArray ( ) : Array . Empty < object > ( ) ;
3435 }
3536
37+ public static object [ ] InvokeRunMethod ( Type [ ] genericArgs , object ? [ ] parameters )
38+ {
39+ var method = typeof ( QueryExecutor )
40+ . GetMethods ( BindingFlags . Static | BindingFlags . Public )
41+ . FirstOrDefault ( m =>
42+ m . Name == "Run" &&
43+ m . IsGenericMethodDefinition &&
44+ m . GetGenericArguments ( ) . Length == genericArgs . Length )
45+ ? . MakeGenericMethod ( genericArgs ) ;
46+
47+ var result = method ? . Invoke ( null , parameters ) ?? Array . Empty < object > ( ) ;
48+ return ( object [ ] ) result ;
49+ }
50+
3651 private static IQueryable < object > BuildQuery < TSource , TTarget > ( DbContext db , IQueryable < TSource > source , Query ? query , IMapper ? mapper = null )
3752 {
3853 if ( query is null )
@@ -222,9 +237,18 @@ private static Expression BuildInExpression<T>(DbContext db, Query? query, Membe
222237
223238 private static IEnumerable < dynamic > RunSubquery ( DbContext db , Query ? query )
224239 {
225- var t = query ? . Entity . ToLower ( CultureInfo . InvariantCulture ) ?? string . Empty ;
226- var p = db . GetType ( ) . GetProperty ( t , BindingFlags . IgnoreCase | BindingFlags . Public | BindingFlags . Instance ) ?? throw new InvalidOperationException ( $ "Property '{ t } ' not found on type '{ db . GetType ( ) } '") ;
227- return p . GetValue ( db ) is not IQueryable < dynamic > q ? Array . Empty < dynamic > ( ) : [ .. q . Run ( query ) ] ;
240+ var propName = query ? . Entity . ToLower ( CultureInfo . InvariantCulture ) ?? string . Empty ;
241+ var prop = db . GetType ( ) . GetProperty ( propName , BindingFlags . IgnoreCase | BindingFlags . Public | BindingFlags . Instance )
242+ ?? throw new InvalidOperationException ( $ "Property '{ propName } ' not found on type '{ db . GetType ( ) } '") ;
243+
244+ var methods = typeof ( QueryExecutor ) . GetMethods ( BindingFlags . Static | BindingFlags . Public ) ;
245+ var method = methods ? . FirstOrDefault ( m => m . CustomAttributes . Count ( ) == 1 ) ;
246+ var dbSet = prop . GetValue ( db ) ?? throw new ValidationException ( $ "DbSet property '{ prop . Name } ' is null in DbContext.") ;
247+ var genericType = prop . PropertyType . GetGenericArguments ( ) . FirstOrDefault ( ) ?? throw new ValidationException ( $ "Missing DbSet generic type") ;
248+ var queryable = dbSet ? . GetType ( ) . GetMethod ( "AsQueryable" ) ? . Invoke ( dbSet , null ) ;
249+
250+ return InvokeRunMethod ( [ genericType ] , [ queryable , query ] ) ;
251+
228252 }
229253
230254 private static dynamic ? ProjectField ( object ? obj , string field )
@@ -242,13 +266,29 @@ private static Expression GetSearchValue(JsonValue? jsonVal, Type targetType)
242266 }
243267
244268 var nonNullableType = Nullable . GetUnderlyingType ( targetType ) ?? targetType ;
245- var value = jsonVal . Deserialize ( targetType ) ;
246269
247- if ( nonNullableType . IsEnum && value is string )
270+ if ( nonNullableType . IsEnum )
248271 {
249- return Expression . Constant ( Enum . Parse ( nonNullableType , ( string ) value ) ) ;
272+ if ( valueKind == JsonValueKind . String )
273+ {
274+ var enumValue = jsonVal . Deserialize < string > ( ) ;
275+ if ( enumValue != null )
276+ {
277+ return Expression . Constant ( Enum . Parse ( nonNullableType , enumValue ) ) ;
278+ }
279+ }
280+ else if ( valueKind == JsonValueKind . Number )
281+ {
282+ var enumValue = jsonVal . Deserialize < int ? > ( ) ;
283+ if ( enumValue != null )
284+ {
285+ return Expression . Constant ( Enum . ToObject ( nonNullableType , enumValue ) ) ;
286+ }
287+ }
250288 }
251289
290+ var value = jsonVal . Deserialize ( targetType ) ;
291+
252292 var convertedValue = Convert . ChangeType ( value , nonNullableType , CultureInfo . InvariantCulture ) ;
253293 return Expression . Constant ( convertedValue , targetType ) ;
254294 }
0 commit comments