EntityFramework LINQ使用字符串和嵌套反射的顺序

时间:2018-02-20 22:11:49

标签: c# entity-framework reflection lambda linq-to-entities

我已经看到了一些类似的问题,但是找不到一个如何解决这个问题的问题 我希望有可能使用字符串作为属性名来订购集合。

型号:

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);
}

但不幸的是,这会返回错误The parameter '' was not bound in the specified LINQ to Entities query expression。我错过了什么?

2 个答案:

答案 0 :(得分:1)

您需要在循环中嵌套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);
}

答案 1 :(得分:1)

我曾经为IQueryables编写了一个扩展方法,用于按字符串:

定义的属性进行排序
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(&#34; Surname&#34;)。