将动态匿名对象添加到LINQ的groupBy表达式中

5

我有以下的Linq表达式:

Func<Entity, object> groupQuery = item => 
     new { a = item.Attributes["name"], item = item.Attributes["number"] };
var result = target.Collection.Entities.GroupBy(groupQuery).ToList();

但是,如果我不知道要分组多少列(例如3而不是2),以及存储在名称列表中的属性名称,我应该如何更改我的groupQuery对象? 我的第一个想法是创建这样的动态对象,但它不起作用。

dynamic groupQuery= new ExpandoObject();
IDictionary<string, object> dictionary = (IDictionary<string, object>)groupQuery;

foreach (string str in Names)
{
   dictionary.Add(str, str);
}

通用算法适用于未知/无限的可能性。我敢打赌,如果你仔细想想,你会发现大约有50个不同的可能性。最好将每个实现(groupQuery)具体地存储在一个字典中,并使用键(半自动)调用它。 - ymz
“但是如果我不知道要分组多少列(例如3而不是2),以及存储在名称列表中的属性名称,那么我应该怎么办?” 那你知道什么呢?一定有些东西是你知道的,比如要按照哪些属性名称进行分组等。 - Ivan Stoev
您可以使用DynamicLinq - Grundy
2个回答

2

与其从groupQuery返回对象,不如返回一个字符串。该字符串将基于您想要分组的对象的属性构建而成。根据配置,它可以以不同的方式生成,例如基于不同的属性。以下是一个展示该思路的代码:

public class A
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
}

public enum GroupByuMode
{
    GroupBy1,
    GroupBy2,
    GroupBy3,
}

...

var list = new List<A>();
for (int i = 0; i < 10; ++i)
    for (int j = 0; j < 10; ++j)
        for (int k = 0; k < 10; ++k)
            list.Add(new A { Property1 = i.ToString(), Property2 = j.ToString(), Property3 = k.ToString() });

var mode = GroupByuMode.GroupBy1;

Func<A, object> func = a =>
{
    if (mode == GroupByuMode.GroupBy1)
        return a.Property1;
    else if (mode == GroupByuMode.GroupBy2)
        return String.Format("{0}_{1}", a.Property1, a.Property2);
    else if (mode == GroupByuMode.GroupBy3)
        return String.Format("{0}_{1}_{2}", a.Property1, a.Property2, a.Property3);

    return null;
};

var res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);

mode = GroupByuMode.GroupBy2;

res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);

如上所示,它可以与LINQ to Objects一起使用。您需要检查它是否适用于LINQ to Entities或另一个LINQ的实现。


它是预定义的,不是动态的 =(但还是谢谢你的回答。 - Anton Kozlovsky

1

在问题中的答案 C# LINQ - 如何动态构建Group By子句

IEnumerable<string> columnsToGroupBy = new[] { Names.First()};
            Names.RemoveAt(0);
            Names.Aggregate(columnsToGroupBy, (current, query) => current.Concat(new[] {query}));
            GroupQuery = r => new NTuple<object>(from column in columnsToGroupBy select r[column]);
///////
    using System;
    using System.Collections.Generic;
    using System.Linq;

    namespace WBTCB.AggregationService.Models.Helpers
    {
        public class NTuple<T> : IEquatable<NTuple<T>>
        {
            public NTuple(IEnumerable<T> values)
            {
                Values = values.ToArray();
            }

            public readonly T[] Values;

            public override bool Equals(object obj)
            {
                if (ReferenceEquals(this, obj))
                    return true;
                if (obj == null)
                    return false;
                return Equals(obj as NTuple<T>);
            }

            public bool Equals(NTuple<T> other)
            {
                if (ReferenceEquals(this, other))
                    return true;
                if (other == null)
                    return false;
                var length = Values.Length;
                if (length != other.Values.Length)
                    return false;
                for (var i = 0; i < length; ++i)
                    if (!Equals(Values[i], other.Values[i]))
                        return false;
                return true;
            }

            public override int GetHashCode()
            {
                return Values.Aggregate(17, (current, value) => current*37 + (!ReferenceEquals(value, null) ? value.GetHashCode() : 0));
            }
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接