EntityFramework 使用字符串和嵌套反射的 LINQ Order
EntityFramework LINQ Order using string and nested reflection
我已经看到了一些类似的问题,但找不到如何解决这个问题的答案。
我希望有可能使用字符串作为 属性 名称来订购集合。
型号:
public sealed class User : IdentityUser
{
#region Constructors
#endregion
#region Properties
[Required]
[Display(Name = "First name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last name")]
public string LastName { get; set; }
[ForeignKey("Superior")]
public string SuperiorId { get; set; }
public User Superior{ get; set; }
[NotMapped]
public string FullName => this.LastName + " " + this.FirstName;
#endregion
}
我想这样打电话:
DbSet.Order("SuperiorUser.FullName", Asc/Desc)...
我的以下函数适用于 Order("FullName", Asc/Desc)
,但当我想更深入时却不行。
public static IOrderedQueryable<T> Order<T>(this IQueryable<T> source, string propertyName,
ListSortDirection direction = ListSortDirection.Ascending)
{
return ListSortDirection.Ascending == direction
? source.OrderBy(ToLambda<T>(propertyName))
: source.OrderByDescending(ToLambda<T>(propertyName));
}
private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T));
var property = Expression.Property(parameter, propertyName);
return Expression.Lambda<Func<T, object>>(property, parameter);
}
所以我让它看起来有点像这样
private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var type = typeof(T)
ParameterExpression parameter;
MemberExpression property;
for (var propName in propertyNames)
{
parameter = Expression.Parameter(type);
property = Expression.Property(parameter, propName);
type = property.Type;
}
return Expression.Lambda<Func<T, object>>(property, parameter);
}
但不幸的是 returns 错误 The parameter '' was not bound in the specified LINQ to Entities query expression
。我错过了什么?
您需要在循环中嵌套 Property
访问方法,然后将参数应用于 lambda。
private static Expression<Func<T, object>> ToLambda<T>(string propertyName) {
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);
return Expression.Lambda<Func<T, object>>(body, parameter);
}
我曾经为 IQueryable 写了一个扩展方法来按 属性 定义的字符串排序:
public static IOrderedQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
else
{
if (propertyName.EndsWith(" ASC", StringComparison.OrdinalIgnoreCase))
propertyName = propertyName.Replace(" ASC", "");
// DataSource control passes the sort parameter with a direction
// if the direction is descending
int descIndex = propertyName.IndexOf(" DESC", StringComparison.OrdinalIgnoreCase);
if (descIndex >= 0)
{
propertyName = propertyName.Substring(0, descIndex).Trim();
}
ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
MemberExpression property = Expression.Property(parameter, propertyName);
LambdaExpression lambda = Expression.Lambda(property, parameter);
string methodName = (descIndex < 0) ? "OrderBy" : "OrderByDescending";
Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
new Type[] { source.ElementType, property.Type },
source.Expression, Expression.Quote(lambda));
return source.Provider.CreateQuery<T>(methodCallExpression) as IOrderedQueryable<T>;
}
}
您可以调用 LIST.AsQueryable().SortBy("Surname").
我已经看到了一些类似的问题,但找不到如何解决这个问题的答案。
我希望有可能使用字符串作为 属性 名称来订购集合。
型号:
public sealed class User : IdentityUser
{
#region Constructors
#endregion
#region Properties
[Required]
[Display(Name = "First name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last name")]
public string LastName { get; set; }
[ForeignKey("Superior")]
public string SuperiorId { get; set; }
public User Superior{ get; set; }
[NotMapped]
public string FullName => this.LastName + " " + this.FirstName;
#endregion
}
我想这样打电话:
DbSet.Order("SuperiorUser.FullName", Asc/Desc)...
我的以下函数适用于 Order("FullName", Asc/Desc)
,但当我想更深入时却不行。
public static IOrderedQueryable<T> Order<T>(this IQueryable<T> source, string propertyName,
ListSortDirection direction = ListSortDirection.Ascending)
{
return ListSortDirection.Ascending == direction
? source.OrderBy(ToLambda<T>(propertyName))
: source.OrderByDescending(ToLambda<T>(propertyName));
}
private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T));
var property = Expression.Property(parameter, propertyName);
return Expression.Lambda<Func<T, object>>(property, parameter);
}
所以我让它看起来有点像这样
private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var type = typeof(T)
ParameterExpression parameter;
MemberExpression property;
for (var propName in propertyNames)
{
parameter = Expression.Parameter(type);
property = Expression.Property(parameter, propName);
type = property.Type;
}
return Expression.Lambda<Func<T, object>>(property, parameter);
}
但不幸的是 returns 错误 The parameter '' was not bound in the specified LINQ to Entities query expression
。我错过了什么?
您需要在循环中嵌套 Property
访问方法,然后将参数应用于 lambda。
private static Expression<Func<T, object>> ToLambda<T>(string propertyName) {
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);
return Expression.Lambda<Func<T, object>>(body, parameter);
}
我曾经为 IQueryable 写了一个扩展方法来按 属性 定义的字符串排序:
public static IOrderedQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
else
{
if (propertyName.EndsWith(" ASC", StringComparison.OrdinalIgnoreCase))
propertyName = propertyName.Replace(" ASC", "");
// DataSource control passes the sort parameter with a direction
// if the direction is descending
int descIndex = propertyName.IndexOf(" DESC", StringComparison.OrdinalIgnoreCase);
if (descIndex >= 0)
{
propertyName = propertyName.Substring(0, descIndex).Trim();
}
ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
MemberExpression property = Expression.Property(parameter, propertyName);
LambdaExpression lambda = Expression.Lambda(property, parameter);
string methodName = (descIndex < 0) ? "OrderBy" : "OrderByDescending";
Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
new Type[] { source.ElementType, property.Type },
source.Expression, Expression.Quote(lambda));
return source.Provider.CreateQuery<T>(methodCallExpression) as IOrderedQueryable<T>;
}
}
您可以调用 LIST.AsQueryable().SortBy("Surname").