C# 如何在实体框架中动态地按表达式构造顺序?
我使用以下方法通过表达式构建顺序 它真的很光滑。缺点是它仅在属性为string类型时有效 我怎样才能在不为不同的数据类型创建一系列方法的情况下接受不同的属性类型C# 如何在实体框架中动态地按表达式构造顺序?,c#,entity-framework,C#,Entity Framework,我使用以下方法通过表达式构建顺序 它真的很光滑。缺点是它仅在属性为string类型时有效 我怎样才能在不为不同的数据类型创建一系列方法的情况下接受不同的属性类型 publicstaticboolpropertyExists(stringpropertyName) { 返回typeof(T).GetProperty(propertyName,BindingFlags.IgnoreCase| BindingFlags.Public | BindingFlags.Instance)!=null; }
publicstaticboolpropertyExists(stringpropertyName)
{
返回typeof(T).GetProperty(propertyName,BindingFlags.IgnoreCase|
BindingFlags.Public | BindingFlags.Instance)!=null;
}
公共静态表达式GetPropertyExpression(字符串propertyName)
{
if(typeof(T).GetProperty(propertyName,BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance)==null)
{
返回null;
}
var parametexpression=Expression.Parameter(typeof(T));
return(Expression)Expression.Lambda(
Expression.PropertyOrField(parametexpression,propertyName),parametexpression);
}
用法
//orderBy可以是Name或City。
if(QueryHelper.PropertyExists(orderBy))
{
var orderByExpression=QueryHelper.GetPropertyExpression(orderBy);
clubQuery=clubQuery.OrderBy(orderByExpression);
}
其他的
{
clubQuery=clubQuery.OrderBy(c=>c.Id);
}
问题
公共班级俱乐部
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串City{get;set;}
public DateTime CreateDate{get;set;}我在的旧答案的帮助下找到了一个解决方案
public static class QueryHelper
{
private static readonly MethodInfo OrderByMethod =
typeof (Queryable).GetMethods().Single(method =>
method.Name == "OrderBy" && method.GetParameters().Length == 2);
private static readonly MethodInfo OrderByDescendingMethod =
typeof (Queryable).GetMethods().Single(method =>
method.Name == "OrderByDescending" && method.GetParameters().Length == 2);
public static bool PropertyExists<T>(this IQueryable<T> source, string propertyName)
{
return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) != null;
}
public static IQueryable<T> OrderByProperty<T>(
this IQueryable<T> source, string propertyName)
{
if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) == null)
{
return null;
}
ParameterExpression paramterExpression = Expression.Parameter(typeof (T));
Expression orderByProperty = Expression.Property(paramterExpression, propertyName);
LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression);
MethodInfo genericMethod =
OrderByMethod.MakeGenericMethod(typeof (T), orderByProperty.Type);
object ret = genericMethod.Invoke(null, new object[] {source, lambda});
return (IQueryable<T>) ret;
}
public static IQueryable<T> OrderByPropertyDescending<T>(
this IQueryable<T> source, string propertyName)
{
if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) == null)
{
return null;
}
ParameterExpression paramterExpression = Expression.Parameter(typeof (T));
Expression orderByProperty = Expression.Property(paramterExpression, propertyName);
LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression);
MethodInfo genericMethod =
OrderByDescendingMethod.MakeGenericMethod(typeof (T), orderByProperty.Type);
object ret = genericMethod.Invoke(null, new object[] {source, lambda});
return (IQueryable<T>) ret;
}
}
我有一个更简单的解决方案:
public static IOrderedQueryable<TSource> Sort<TSource>(this IQueryable<TSource> source, bool ascending , string sortingProperty)
{
if (ascending)
return source.OrderBy(item => item.GetReflectedPropertyValue(sortingProperty));
else
return source.OrderByDescending(item => item.GetReflectedPropertyValue(sortingProperty));
}
private static object GetReflectedPropertyValue(this object subject, string field)
{
return subject.GetType().GetProperty(field).GetValue(subject, null);
}
myQueryableCollection.Sort(ascending: true, "Name")
当然,PropertyExist()
helper是一个很好的补充…因此它位于var orderByExpression=queryhelp.GetPropertyExpression(orderBy)
这是问题的原因吗?问题是每种数据类型都有太多重复的代码。请参考我发布的上一个代码。对于使用dynamic OrderBy的人来说,这似乎是一个非常常见的问题;但我在Google中找不到任何解决方案。我愿意接受任何建议或替代方法。而不是输入“CreateDate”或“Name”或“城市”否则,我会传入某种表示要排序的属性的对象。这个对象将能够生成排序表达式和其他有用的东西。更多的代码,但如果是丛林,就不会有混乱。@MikeChristensen返回的表达式?@moarboilerplate-Hmm,我想LambdaExpressio是什么类型的n
?表达式
给你的唯一东西是他可能不需要的编译
和更新
。我们真的希望其他人有答案吗?;)是否可以修改它来对当前实体的导航属性进行排序?很好的解决方案!我唯一的问题是如何按子项排序nate对象?例如,如果我有一个对象Apple{Kernel{Size=13}
,我如何对Size
属性的查询排序?将示例中的orderBy
设置为“Kernel.Size”
不起作用。这在EF Core 3.1中不起作用。关于如何使其正常工作,有什么建议吗?嗨,这在EF Core 3中起作用吗?它为我抛出:.OrderByDescending(e0=>(object)e0.GetReflectedPropertyValue(u filter_Sort_Predicate_3))'无法翻译。请以可以翻译的形式重写查询,或者通过插入对AsEnumerable()、AsAsAsAsyncEnumerable()、ToLi st()或ToListSync()的调用显式切换到客户端计算。有关详细信息,请参阅。不起作用:LINQ表达式'DbSet.Where(i=>…)。OrderBy(i=>(对象)无法转换i.GetReflectedPropertyValue(\uu sortingProperty\u 0))。
public static Expression<Func<TSource, TKey>>
GetPropertyExpression<TSource, TKey>(string propertyName)
{
if (typeof (TSource).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) == null)
{
return null;
}
var paramterExpression = Expression.Parameter(typeof (TSource));
return (Expression<Func<TSource, TKey>>)
Expression.Lambda(Expression.PropertyOrField(
paramterExpression, propertyName), paramterExpression);
}
if (QueryHelper.PropertyExists<Club>(orderBy))
{
if(orderBy == "CreateDate")
{
var orderByExpression = GetPropertyExpression<Club, DateTime>(orderBy);
...
}
else if(orderBy == "Name" || orderBy == "City")
{
var orderByExpression = GetPropertyExpression<Club, string>(orderBy);
...
}
...
}
else
{
clubQuery = clubQuery.OrderBy(c => c.Id);
}
public static class QueryHelper
{
private static readonly MethodInfo OrderByMethod =
typeof (Queryable).GetMethods().Single(method =>
method.Name == "OrderBy" && method.GetParameters().Length == 2);
private static readonly MethodInfo OrderByDescendingMethod =
typeof (Queryable).GetMethods().Single(method =>
method.Name == "OrderByDescending" && method.GetParameters().Length == 2);
public static bool PropertyExists<T>(this IQueryable<T> source, string propertyName)
{
return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) != null;
}
public static IQueryable<T> OrderByProperty<T>(
this IQueryable<T> source, string propertyName)
{
if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) == null)
{
return null;
}
ParameterExpression paramterExpression = Expression.Parameter(typeof (T));
Expression orderByProperty = Expression.Property(paramterExpression, propertyName);
LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression);
MethodInfo genericMethod =
OrderByMethod.MakeGenericMethod(typeof (T), orderByProperty.Type);
object ret = genericMethod.Invoke(null, new object[] {source, lambda});
return (IQueryable<T>) ret;
}
public static IQueryable<T> OrderByPropertyDescending<T>(
this IQueryable<T> source, string propertyName)
{
if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance) == null)
{
return null;
}
ParameterExpression paramterExpression = Expression.Parameter(typeof (T));
Expression orderByProperty = Expression.Property(paramterExpression, propertyName);
LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression);
MethodInfo genericMethod =
OrderByDescendingMethod.MakeGenericMethod(typeof (T), orderByProperty.Type);
object ret = genericMethod.Invoke(null, new object[] {source, lambda});
return (IQueryable<T>) ret;
}
}
string orderBy = "Name";
if (query.PropertyExists(orderBy))
{
query = query.OrderByProperty(orderBy);
- OR -
query = query.OrderByPropertyDescending(orderBy);
}
public static IOrderedQueryable<TSource> Sort<TSource>(this IQueryable<TSource> source, bool ascending , string sortingProperty)
{
if (ascending)
return source.OrderBy(item => item.GetReflectedPropertyValue(sortingProperty));
else
return source.OrderByDescending(item => item.GetReflectedPropertyValue(sortingProperty));
}
private static object GetReflectedPropertyValue(this object subject, string field)
{
return subject.GetType().GetProperty(field).GetValue(subject, null);
}
myQueryableCollection.Sort(ascending: true, "Name")