使用 Linq.Expression 通过动态 lambda 访问嵌套属性

发布于 2024-08-10 04:36:21 字数 1044 浏览 1 评论 0原文

假设我有两个类:

class person
{
    int ID
    string name
    Address address
}
class address
{
    int ID
    string street
    string country
}

这些类或多或少是给定的,老实说它们是通过 nHibernate 映射的:)

在网格中 (datatables.net 作为基础)我想要进行与类型无关的排序。

因此,我创建了一个 lambda 表达式:

  var param = Expression.Parameter(typeof(T), typeof(T).Name);
  var sortExpression = Expression.Lambda<Func<T, object>>
                              (Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param);

如果我将 Person 作为类型 T 传递,并将“要排序的属性”替换为“名称”,则它可以正常工作(创建正确的 lambda)。如果要排序的属性是“address.street”,它将不起作用,请向我抛出以下错误:

Property 'address.street' is not defined for type 'person'

到目前为止,我只看到一个解决方案,但不够清晰......我会尝试拆分包含该属性的字符串-名称(用 分隔。)

任何人都可以提供更好的解决方案吗?我需要将 sortExpression 添加到 IQueryable 对象query.OrderBy(sortExpression)

不知道我的标题是否清楚,请大家指正。

提前致谢。

Let's assume that I have two classes:

class person
{
    int ID
    string name
    Address address
}
class address
{
    int ID
    string street
    string country
}

These classes are more or less given, they are mapped via nHibernate to be honest :)

In a grid (datatables.net as base) I would like to have a type-independent sorting.

Therefore I created a lambda expression:

  var param = Expression.Parameter(typeof(T), typeof(T).Name);
  var sortExpression = Expression.Lambda<Func<T, object>>
                              (Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param);

If I pass Person as Type T and replace the "Property to sort" with "name" it works fine (creates a correct lambda). If the Property to sort is "address.street" it won't work, throw me the following error:

Property 'address.street' is not defined for type 'person'

I see only one solution so far, but not clear enough... I would try to split the string which contains the Property-Name (split by .)

Can anyone give a better solution? I need to add the sortExpression to an IQueryable object query.OrderBy(sortExpression).

Not sure if my title is clear, please go ahead and correct it.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

追我者格杀勿论 2024-08-17 04:36:21

什么不清楚?

您必须将其拆分然后使用:

Expression.Property(Expression.Property(param, "address"), "street")

What is not clear?

You have to split it and then use:

Expression.Property(Expression.Property(param, "address"), "street")
尘世孤行 2024-08-17 04:36:21

这是 LukLed 答案的更通用版本:

    protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
    {
        string[] parts = propertyName.Split('.');
        int partsL = parts.Length;

        return (partsL > 1) 
            ? 
            Expression.Property( 
                NestedExpressionProperty(
                    expression, 
                    parts.Take(partsL - 1)
                        .Aggregate((a, i) => a + "." + i)
                ), 
                parts[partsL - 1]) 
            :
            Expression.Property(expression, propertyName);
    }

您可以这样使用它:

var paramExpression = Expression.Parameter(this.type, "val");
var firstProp = NestedExpressionProperty(paramExpression,"address.street");

Here's a more generic version of LukLed's answer:

    protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
    {
        string[] parts = propertyName.Split('.');
        int partsL = parts.Length;

        return (partsL > 1) 
            ? 
            Expression.Property( 
                NestedExpressionProperty(
                    expression, 
                    parts.Take(partsL - 1)
                        .Aggregate((a, i) => a + "." + i)
                ), 
                parts[partsL - 1]) 
            :
            Expression.Property(expression, propertyName);
    }

You can use it like this:

var paramExpression = Expression.Parameter(this.type, "val");
var firstProp = NestedExpressionProperty(paramExpression,"address.street");
淡淡绿茶香 2024-08-17 04:36:21

在我看来,你正在尝试重写 Microsoft DynamicQuery。为什么不直接使用它呢?

这是一个例子:

IQueryable<Foo> myQuery = GetHibernateQuery();
myQuery = myQuery.OrderBy("address.street");

It seems to me you're trying to rewrite Microsoft DynamicQuery. Why not just use that instead?

Here's an example:

IQueryable<Foo> myQuery = GetHibernateQuery();
myQuery = myQuery.OrderBy("address.street");
沫尐诺 2024-08-17 04:36:21

试试这个

    public static IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder)
    {
        if (string.IsNullOrWhiteSpace(fieldName)) return data;
        if (string.IsNullOrWhiteSpace(sortOrder)) return data;

        var param = Expression.Parameter(typeof(T), "i");

        MemberExpression property = null;
        string[] fieldNames = fieldName.Split('.');
        foreach (string filed in fieldNames)
        {
            if (property == null)
            {
                property = Expression.Property(param, filed);
            }
            else
            {
                property = Expression.Property(property, filed);
            }
        }

        Expression conversion = Expression.Convert(property, typeof(object));//Expression.Property(param, fieldName)
        var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param);

        return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression)
            : data.OrderBy(mySortExpression);
    }

Try this one

    public static IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder)
    {
        if (string.IsNullOrWhiteSpace(fieldName)) return data;
        if (string.IsNullOrWhiteSpace(sortOrder)) return data;

        var param = Expression.Parameter(typeof(T), "i");

        MemberExpression property = null;
        string[] fieldNames = fieldName.Split('.');
        foreach (string filed in fieldNames)
        {
            if (property == null)
            {
                property = Expression.Property(param, filed);
            }
            else
            {
                property = Expression.Property(property, filed);
            }
        }

        Expression conversion = Expression.Convert(property, typeof(object));//Expression.Property(param, fieldName)
        var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param);

        return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression)
            : data.OrderBy(mySortExpression);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文