对嵌套对象按linq分组

本文关键字:linq 分组 对象 嵌套 | 更新日期: 2023-09-27 18:01:22

我正在制作一个由linq语句组成的组,其中我将单个数据列表转换为具有嵌套列表的列表。下面是我到目前为止的代码:

[TestMethod]
public void LinqTestNestedSelect2()
{
    // initialization 
    List<combi> listToLinq = new List<combi>() { 
        new combi{ id = 1, desc = "a", name = "A", count = 1 },
        new combi{ id = 1, desc = "b", name = "A", count = 2 },
        new combi{ id = 2, desc = "c", name = "B", count = 3 },
        new combi{id = 2,  desc = "d", name = "B", count = 4 },
    };
    // linq group by
    var result = (from row in listToLinq
                  group new { des = row.desc, count = row.count } by new { name = row.name, id = row.id } into obj
                  select new A { name = obj.Key.name, id = obj.Key.id, descriptions = (from r in obj select new B() { des = r.des, count = r.count }).ToList() }).ToList();
    // validation of the results
    Assert.AreEqual(2, result.Count);
    Assert.AreEqual(2, result[0].descriptions.Count);
    Assert.AreEqual(2, result[0].descriptions.Count);
    Assert.AreEqual(2, result[1].descriptions.Count);
    Assert.AreEqual(2, result[1].descriptions.Count);
}
public class A
{
    public int id;
    public string name;
    public List<B> descriptions;
}
public class B
{
    public int count;
    public string des;
}
public class combi
{
    public int id;
    public string name;
    public int count;
    public string desc;
}

如果对象像示例一样小,这很好。然而,我将为具有更多属性的对象实现这一点。我怎样才能有效地编写这条语句,这样我就不必在linq语句中写两次字段名了?

我想返回语句中的对象,我想要这样的:

// not working wishfull thinking code 
var result = (from row in listToLinq
              group new { des = row.desc, count = row.count } by new { name = row.name, id = row.id } into obj
              select new (A){ this = obj.key , descriptions = obj.ToList<B>()}).ToList();

Background:我正在重写一个web api,检索对象嵌套的对象在一个单一的数据库调用db性能的缘故。它基本上是一个大的查询与连接检索垃圾负载的数据,我需要整理成对象。
可能很重要: ID是唯一的

编辑:

根据到目前为止的答案,我已经制定了一个解决方案,它对我来说是有效的,但仍然有点丑,我希望它更好看。

{
    // start part
    return (from row in reader.AsEnumerable()
            group row by row.id into grouping
            select CreateA(grouping)).ToList();
}
private static A CreateA(IGrouping<object, listToLinq> grouping)
{
     A retVal = StaticCreateAFunction(grouping.First());
    retVal.descriptions = grouping.Select(item => StaticCreateBFunction(item)).ToList();
    return ret;
}

我希望staticcreatefunction对于它的作用是足够明显的。在这种情况下,我只需要写出每个属性一次,这正是我真正想要的。但我希望有一个更聪明的方式来写这个

对嵌套对象按linq分组

var result = (from row in listToLinq
              group new B { des = row.desc, count = row.count } by new A { name = row.name, id = row.id } into obj
              select new A { name = obj.Key.name, id = obj.Key.id, descriptions = obj.ToList() }).ToList();

您可以向每个AB类添加一个构造函数,该构造函数接收combi,然后它只从中获取所需的内容。例如对于a:

public class A
{
    public A(combi c)
    {
        id = c.id;
        name = c.name;
    }
}   
public class B
{
    public B(combi c)
    {
        count = c.count;
        des = c.desc;
    }
}

那么你的查询可以看起来像:

var result = (from row in listToLinq
              group row by new { row.id, row.name } into grouping
              select new A(grouping.First())
              {
                  descriptions = grouping.Select(item => new B(item)).ToList()
              }).ToList();

如果你不喜欢grouping.First(),你可以覆盖EqualsGetHashCode,然后在group by中通过一个新的a做相关字段(这将是Equals中的那些),然后从a中添加copy constructor

A/B类与combi解耦的另一种方法是将转换逻辑提取为静态方法的集合。