mirror of
https://github.com/Biarity/Sieve.git
synced 2025-08-17 22:55:32 +02:00
OrderByDynamic is modified to be able to handle inherited members, such as interface members.
SieveProcessor is modified to pass propertyInfo to OrderByDynamic to avoid reattainment of propertyInfo required in Expression.MakeMemberAccess. SieveProcessor is modified to be able to handle possible multiple incompatible customMethods via AggregateException. Corresponding interfaces are generated for entities with related inheritance. ApplicationSieveProcessor is modified to include interface members. SieveCustomFilterMethods and SieveCustomSortMethod are modified to include interface related custom method modifications. Interface accessed unit tests are added.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Sieve.Extensions
|
||||
{
|
||||
@@ -9,10 +10,11 @@ namespace Sieve.Extensions
|
||||
public static IQueryable<TEntity> OrderByDynamic<TEntity>(
|
||||
this IQueryable<TEntity> source,
|
||||
string fullPropertyName,
|
||||
PropertyInfo propertyInfo,
|
||||
bool desc,
|
||||
bool useThenBy)
|
||||
{
|
||||
var lambda = GenerateLambdaWithSafeMemberAccess<TEntity>(fullPropertyName);
|
||||
var lambda = GenerateLambdaWithSafeMemberAccess<TEntity>(fullPropertyName, propertyInfo);
|
||||
|
||||
var command = desc
|
||||
? (useThenBy ? "ThenByDescending" : "OrderByDescending")
|
||||
@@ -28,7 +30,11 @@ namespace Sieve.Extensions
|
||||
return source.Provider.CreateQuery<TEntity>(resultExpression);
|
||||
}
|
||||
|
||||
private static Expression<Func<TEntity, object>> GenerateLambdaWithSafeMemberAccess<TEntity>(string fullPropertyName)
|
||||
private static Expression<Func<TEntity, object>> GenerateLambdaWithSafeMemberAccess<TEntity>
|
||||
(
|
||||
string fullPropertyName,
|
||||
PropertyInfo propertyInfo
|
||||
)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(TEntity), "e");
|
||||
Expression propertyValue = parameter;
|
||||
@@ -36,7 +42,15 @@ namespace Sieve.Extensions
|
||||
|
||||
foreach (var name in fullPropertyName.Split('.'))
|
||||
{
|
||||
propertyValue = Expression.PropertyOrField(propertyValue, name);
|
||||
try
|
||||
{
|
||||
propertyValue = Expression.PropertyOrField(propertyValue, name);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// name is not a direct property of field of propertyValue expression. construct a memberAccess then.
|
||||
propertyValue = Expression.MakeMemberAccess(propertyValue, propertyInfo);
|
||||
}
|
||||
|
||||
if (propertyValue.Type.IsNullable())
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
@@ -340,7 +341,7 @@ namespace Sieve.Services
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
result = result.OrderByDynamic(fullName, sortTerm.Descending, useThenBy);
|
||||
result = result.OrderByDynamic(fullName, property, sortTerm.Descending, useThenBy);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -461,16 +462,35 @@ namespace Sieve.Services
|
||||
}
|
||||
else
|
||||
{
|
||||
var incompatibleCustomMethod = parent?.GetType()
|
||||
.GetMethod(name,
|
||||
_options.Value.CaseSensitive ? BindingFlags.Default : BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
|
||||
var incompatibleCustomMethods = parent?
|
||||
.GetType()
|
||||
.GetMethods
|
||||
(
|
||||
_options.Value.CaseSensitive
|
||||
? BindingFlags.Default
|
||||
: BindingFlags.IgnoreCase | BindingFlags.Public |
|
||||
BindingFlags.Instance
|
||||
)
|
||||
.Where(method => string.Equals(method.Name, name,
|
||||
_options.Value.CaseSensitive
|
||||
? StringComparison.InvariantCulture
|
||||
: StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToList()
|
||||
??
|
||||
new List<MethodInfo>();
|
||||
|
||||
if (incompatibleCustomMethod != null)
|
||||
if (incompatibleCustomMethods.Any())
|
||||
{
|
||||
var expected = typeof(IQueryable<TEntity>);
|
||||
var actual = incompatibleCustomMethod.ReturnType;
|
||||
throw new SieveIncompatibleMethodException(name, expected, actual,
|
||||
$"{name} failed. Expected a custom method for type {expected} but only found for type {actual}");
|
||||
var incompatibles =
|
||||
from incompatibleCustomMethod in incompatibleCustomMethods
|
||||
let expected = typeof(IQueryable<TEntity>)
|
||||
let actual = incompatibleCustomMethod.ReturnType
|
||||
select new SieveIncompatibleMethodException(name, expected, actual,
|
||||
$"{name} failed. Expected a custom method for type {expected} but only found for type {actual}");
|
||||
|
||||
var aggregate = new AggregateException(incompatibles);
|
||||
|
||||
throw new SieveIncompatibleMethodException(aggregate.Message, aggregate);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Reference in New Issue
Block a user