使用字符串字段名称动态构建带层次结构的linq查询?

时间:2014-05-13 01:01:09

标签: c# linq linq-to-objects

我难以接受..我需要取一个对象的平面列表,一些字段名称数组作为字符串(分组,分类,选择哪个)在运行时以某种方式生成LINQ查询以返回JSON序列化的对象。

我在设置下面构建了一个示例repro。 OrderBy很简单,我只是使用GetType()。GetProperty()来查找正确的属性,并将orderby字段迭代到菊花链.OrderBy调用。这一切都在GroupBy上崩溃,因为每个人都将结果包装在IEnumerable> ..

这样做有好办法吗?我在网上找到的所有东西都让人们诉诸于旧的递归程序代码。 LINQ必须有办法做到这一点,但我迷失了。我尝试的所有东西都无法编译,这些类型只是赢得了匹配......

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic;

namespace linqtest2
{
    class Program
    {
        static void Main(string[] args)
        {
            var products = new List<Product>
                {
                    new Product("Food", "Fruit", "Apple"),
                    new Product("Food", "Fruit", "Banana"),
                    new Product("Food", "Fruit", "Orange"),
                    new Product("Food", "Vegetables", "Carrot"),
                    new Product("Food", "Vegetables", "Pea"),
                    new Product("Drink", "Soft Drink", "Orange Juice"),
                    new Product("Drink", "Soft Drink", "Lemonade"),
                    new Product("Drink", "Alcoholic", "Bitter"),
                    new Product("Drink", "Alcoholic", "Lager"),
                    new Product("Drink", "Alcoholic", "Vodka")
                };

            string[] select = new[] { "Category", "Name" };
            string[] orderBy = new[] { "Name", "Category" };
            string[] groupBy = new[] { "Category", "Subcategory" };
        }
    }

    public class Product
    {
        public string Name { get; set; }
        public string Category { get; set; }
        public string Subcategory { get; set; }

        public Product(string category, string subcategory, string name)
        {
            Category = category;
            Subcategory = subcategory;
            Name = name;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

请检查Dynamic Linq库,它提供了一种使用字符串而不是lambdas的方法。

使用动态linq,您可以写:

products.OrderBy("Category").ThenBy("Name")

还有很多其他可能性。

修改

将解决方案更新为更具动态性

IQueryable<Product> query = products;
bool firstOrderBy = true;
foreach(var orderExpression in orderBy)
{
    if (firstOrderBy)
    {
        query = query.OrderBy(orderExpression);
        firstOrderBy = false;
    }
    else
    {
        query = query.ThenBy(orderExpression);
    }
}

正如我建议的那样,验证库,探索它并根据您的需要进行调整。您也可以使用 GroupBy 选择

同时检查@dkackman提出的解决方案,看看哪种解决方案更适合您的需求,您需要做一些解决方案来满足您的需求。

答案 1 :(得分:2)

Linq语法实际上是在编译时知道数据的静态结构。底层System.Linq.Expressions命名空间具有创建运行时的巨大能力,而不是编译时绑定,但是在使用时它是相当费力的。

为了支持动态输入输入和输出,您可以通过使用某些库来获得最佳效果。

@pgio建议的动态Linq是一个选项。

SqlLinq是另一个。使用SqlLinq,您可以将整个查询动态地构建为字符串并执行如下操作:

var products = new List<Product>
    {
        new Product("Food", "Fruit", "Apple"),
        new Product("Food", "Fruit", "Banana"),
        new Product("Food", "Fruit", "Orange"),
        new Product("Food", "Vegetables", "Carrot"),
        new Product("Food", "Vegetables", "Pea"),
        new Product("Drink", "Soft Drink", "Orange Juice"),
        new Product("Drink", "Soft Drink", "Lemonade"),
        new Product("Drink", "Alcoholic", "Bitter"),
        new Product("Drink", "Alcoholic", "Lager"),
        new Product("Drink", "Alcoholic", "Vodka")
    };

var results = products.Query<Product, dynamic>("SELECT category, subcategory, count(*) AS cnt FROM this GROUP BY category, subcategory ORDER BY category, subcategory");

foreach(dynamic d in results)
{
    Debug.WriteLine("{0} {1} {2}", (string)d.category, (string)d.subcategory, (int)d.cnt);
}