Skip to content

Commit be976a1

Browse files
Get proper generic type in RunSubquery method
1 parent e72480a commit be976a1

File tree

2 files changed

+47
-27
lines changed

2 files changed

+47
-27
lines changed

QueryExecutor.cs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
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.Collections.Generic;
72
using System.Globalization;
83
using System.Linq.Expressions;
94
using System.Reflection;
105
using System.Reflection.Emit;
116
using System.Text.Json;
127
using System.Text.Json.Nodes;
138
using 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

1516
namespace Infragistics.QueryBuilder.Executor
1617
{
@@ -33,6 +34,15 @@ 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 MethodInfo? GetGenericMethod(Type executorType, int attributeCount, Type[] genericArgs)
38+
{
39+
var method = executorType
40+
.GetMethods(BindingFlags.Static | BindingFlags.Public)
41+
.FirstOrDefault(m => m.CustomAttributes.Count() == attributeCount);
42+
43+
return method?.MakeGenericMethod(genericArgs);
44+
}
45+
3646
private static IQueryable<object> BuildQuery<TSource, TTarget>(DbContext db, IQueryable<TSource> source, Query? query, IMapper? mapper = null)
3747
{
3848
if (query is null)
@@ -224,7 +234,21 @@ private static IEnumerable<dynamic> RunSubquery(DbContext db, Query? query)
224234
{
225235
var t = query?.Entity.ToLower(CultureInfo.InvariantCulture) ?? string.Empty;
226236
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)];
237+
238+
var methods = typeof(QueryExecutor).GetMethods(BindingFlags.Static | BindingFlags.Public);
239+
var method = methods?.FirstOrDefault(m => m.CustomAttributes.Count() == 1);
240+
var dbSet = p.GetValue(db);
241+
var genericType = p.PropertyType.GetGenericArguments().FirstOrDefault();
242+
243+
if (dbSet != null && genericType != null)
244+
{
245+
246+
var genericMethod = GetGenericMethod(typeof(QueryExecutor), 1, [genericType]);
247+
248+
var queryable = dbSet?.GetType().GetMethod("AsQueryable")?.Invoke(dbSet, null);
249+
return genericMethod?.Invoke(null, [queryable, query]) as IEnumerable<dynamic> ?? Array.Empty<dynamic>();
250+
}
251+
return Enumerable.Empty<dynamic>();
228252
}
229253

230254
private static dynamic? ProjectField(object? obj, string field)
@@ -242,13 +266,18 @@ 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+
var enumValue = jsonVal.Deserialize<string>();
273+
if (enumValue != null)
274+
{
275+
return Expression.Constant(Enum.Parse(nonNullableType, enumValue));
276+
}
250277
}
251278

279+
var value = jsonVal.Deserialize(targetType);
280+
252281
var convertedValue = Convert.ChangeType(value, nonNullableType, CultureInfo.InvariantCulture);
253282
return Expression.Constant(convertedValue, targetType);
254283
}

Services/QueryBuilderService.cs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,18 @@ public Dictionary<string, object[]> RunQuery(Query query)
1818
.FirstOrDefault(p => p.PropertyType.IsGenericType && p.Name.ToLower(CultureInfo.InvariantCulture) == t && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>));
1919
if (propInfo != null)
2020
{
21-
var methods = typeof(QueryExecutor).GetMethods(BindingFlags.Static | BindingFlags.Public);
22-
var method = methods?.FirstOrDefault(m => m.CustomAttributes.Count() == 2);
23-
2421
var dbSet = propInfo.GetValue(db);
2522
var dbGenericType = dbSet?.GetType()?.GenericTypeArguments.FirstOrDefault();
26-
if (dbGenericType != null && dbSet != null)
23+
var dtoGenericType = typeof(TResults).GetProperty(propInfo.Name)?.PropertyType.GetElementType();
24+
25+
if (dbSet != null && dbGenericType != null && dtoGenericType != null)
2726
{
28-
var dtoGenericType = typeof(TResults).GetProperty(propInfo.Name)?.PropertyType.GetElementType();
29-
if (dtoGenericType != null)
30-
{
31-
var genericMethod = method?.MakeGenericMethod(dbGenericType, dtoGenericType);
27+
var genericMethod = QueryExecutor.GetGenericMethod(typeof(QueryExecutor), 2, [dbGenericType, dtoGenericType]);
3228

33-
var asQueryableMethod = dbSet.GetType().GetMethod("AsQueryable");
34-
var queryable = asQueryableMethod?.Invoke(dbSet, null);
35-
if (queryable != null)
36-
{
37-
if (genericMethod?.Invoke(null, [queryable, query, mapper]) is object[] propRes)
38-
{
39-
return new Dictionary<string, object[]> { { propInfo.Name, propRes } };
40-
}
41-
}
29+
var queryable = dbSet.GetType().GetMethod("AsQueryable")?.Invoke(dbSet, null);
30+
if (queryable != null && genericMethod?.Invoke(null, [queryable, query, mapper]) is object[] propRes)
31+
{
32+
return new Dictionary<string, object[]> { { propInfo.Name.ToLowerInvariant(), propRes } };
4233
}
4334
}
4435
}

0 commit comments

Comments
 (0)