由linq分组用于嵌套对象

时间:2016-08-08 13:47:31

标签: c# linq

我正在通过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();

背景:我正在编写一个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;
}

我希望StaticCreateAFunction足够明显。在这种情况下,我只需要写出一次属性,这就是我真正想要的。但是我希望有一种更聪明或更流行的方式来写这个。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

您可以向每个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 1}}包含相关字段(将是Equals中的字段),然后从copy constructor

添加a

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