У вас две проблемы с вашим подходом.Во-первых, вы не можете использовать нулевой распространяющий оператор в выражениях Linq.Протестируйте этот код:
var account = new Account();
// will cause "error CS8072: An expression tree lambda may not contain a null propagating operator"
Expression<Func<string>> accountNumber = () => account?.AccountNumber;
Вторая и главная проблема заключается в том, что ваш AccountNumber
будет скомпилирован в метод get_AccountNumber
, и вы не можете вызывать произвольные методы с Linq to SQL.Вы можете протестировать этот код:
public class AssetFileRecord
{
//...
public string AccountNumber => Account != null ? Account.AccountNumber : null;
}
, хотя это может быть скомпилировано, оно выдает то же исключение времени выполнения.
Один из возможных способов обойти эту проблему - создать карту с выражениями для сложных свойств.:
var map = new Dictionary<string, Expression>
{
{
"AssetFileRecord.AccountNumber", // type and property
(Expression<Func<AssetFileRecord, string>>) (
afr => afr.Account != null ? afr.Account.AccountNumber : null
)
}
};
Теперь вы можете переписать свой метод, который строит динамически OrderBy
относительно этой карты:
private static IQueryable<T> DynamicOrderBy<T>(
IQueryable<T> source,
string sortProperty,
Dictionary<string, Expression> map)
{
var type = typeof(T);
var parameter = Expression.Parameter(type, "p");
var property = type.GetProperty(sortProperty, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
Expression whereLambda;
if (!map.TryGetValue($"{type.Name}.{sortProperty}", out whereLambda))
{
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
whereLambda = Expression.Lambda(propertyAccess, parameter);
}
// else we just using a lambda from map
// call OrderBy
var query = Expression.Call(
typeof(Queryable),
"OrderBy",
new[] {type, property.PropertyType},
source.Expression,
whereLambda
);
return source.Provider.CreateQuery<T>(query);
}