Skip to content

Commit 3c8a950

Browse files
Update from master
1 parent daf0d5e commit 3c8a950

File tree

2 files changed

+41
-72
lines changed

2 files changed

+41
-72
lines changed

QueryExecutor.cs

Lines changed: 12 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
using System.ComponentModel.DataAnnotations;
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;
27
using System.Globalization;
38
using System.Linq.Expressions;
49
using System.Reflection;
510
using System.Reflection.Emit;
611
using System.Text.Json;
712
using System.Text.Json.Nodes;
813
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;
1514

1615
namespace Infragistics.QueryBuilder.Executor
1716
{
@@ -34,20 +33,6 @@ public static object[] Run<TSource, TTarget>(this IQueryable<TSource> source, Qu
3433
return db is not null ? BuildQuery<TSource, TTarget>(db, source, query, mapper).ToArray() : Array.Empty<object>();
3534
}
3635

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-
5136
private static IQueryable<object> BuildQuery<TSource, TTarget>(DbContext db, IQueryable<TSource> source, Query? query, IMapper? mapper = null)
5237
{
5338
if (query is null)
@@ -237,18 +222,9 @@ private static Expression BuildInExpression<T>(DbContext db, Query? query, Membe
237222

238223
private static IEnumerable<dynamic> RunSubquery(DbContext db, Query? query)
239224
{
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-
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)];
252228
}
253229

254230
private static dynamic? ProjectField(object? obj, string field)
@@ -266,29 +242,13 @@ private static Expression GetSearchValue(JsonValue? jsonVal, Type targetType)
266242
}
267243

268244
var nonNullableType = Nullable.GetUnderlyingType(targetType) ?? targetType;
245+
var value = jsonVal.Deserialize(targetType);
269246

270-
if (nonNullableType.IsEnum)
247+
if (nonNullableType.IsEnum && value is string)
271248
{
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-
}
249+
return Expression.Constant(Enum.Parse(nonNullableType, (string)value));
288250
}
289251

290-
var value = jsonVal.Deserialize(targetType);
291-
292252
var convertedValue = Convert.ChangeType(value, nonNullableType, CultureInfo.InvariantCulture);
293253
return Expression.Constant(convertedValue, targetType);
294254
}

Services/QueryBuilderService.cs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
using System.ComponentModel.DataAnnotations;
2-
using System.Globalization;
3-
using System.Reflection;
4-
using AutoMapper;
1+
using AutoMapper;
52
using Microsoft.EntityFrameworkCore;
63
using Microsoft.Extensions.Logging;
4+
using System.Globalization;
5+
using System.Reflection;
76

87
namespace Infragistics.QueryBuilder.Executor
98
{
@@ -16,25 +15,35 @@ public Dictionary<string, object[]> RunQuery(Query query)
1615
var t = query.Entity.ToLower(CultureInfo.InvariantCulture);
1716

1817
var propInfo = db?.GetType().GetProperties()
19-
.FirstOrDefault(p =>
20-
p.PropertyType.IsGenericType &&
21-
p.Name.ToLower(CultureInfo.InvariantCulture) == t &&
22-
p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
23-
?? throw new InvalidOperationException($"Unknown entity {t}");
24-
25-
var dbSet = propInfo.GetValue(db) ?? throw new ValidationException($"DbSet property '{propInfo.Name}' is null in DbContext.");
26-
var dbGenericType = dbSet.GetType().GenericTypeArguments.FirstOrDefault() ?? throw new ValidationException($"Missing DbSet generic type");
27-
28-
var resultProperty = typeof(TResults).GetProperty(t, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
29-
?? throw new ValidationException($"Unknown entity {t}");
18+
.FirstOrDefault(p => p.PropertyType.IsGenericType && p.Name.ToLower(CultureInfo.InvariantCulture) == t && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>));
19+
if (propInfo != null)
20+
{
21+
var methods = typeof(QueryExecutor).GetMethods(BindingFlags.Static | BindingFlags.Public);
22+
var method = methods?.FirstOrDefault(m => m.CustomAttributes.Count() == 2);
3023

31-
var dtoGenericType = resultProperty.PropertyType.GetElementType() ?? throw new ValidationException($"Missing Dto generic type");
24+
var dbSet = propInfo.GetValue(db);
25+
var dbGenericType = dbSet?.GetType()?.GenericTypeArguments.FirstOrDefault();
26+
if (dbGenericType != null && dbSet != null)
27+
{
28+
var dtoGenericType = typeof(TResults).GetProperty(propInfo.Name)?.PropertyType.GetElementType();
29+
if (dtoGenericType != null)
30+
{
31+
var genericMethod = method?.MakeGenericMethod(dbGenericType, dtoGenericType);
3232

33-
var queryable = dbSet.GetType().GetMethod("AsQueryable")?.Invoke(dbSet, null)
34-
?? throw new InvalidOperationException($"DbSet '{propInfo.Name}' does not support AsQueryable().");
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+
}
42+
}
43+
}
44+
}
3545

36-
var propRes = QueryExecutor.InvokeRunMethod([dbGenericType, dtoGenericType], [queryable, query, mapper]);
37-
return new Dictionary<string, object[]> { { propInfo.Name.ToLowerInvariant(), propRes } };
46+
throw new InvalidOperationException($"Unknown entity {t}");
3847
}
3948
}
4049
}

0 commit comments

Comments
 (0)