如何使用Linq将此父级和子级对象模型投影到平坦的单个对象中?

时间:2011-09-08 01:37:08

标签: c# .net linq linq-to-objects

我正试图将一个包含父+子数组的简单类压缩成一个类。

自:

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<PewPew> PewPews { get; set; }
}

public class PewPew
{
    public string Name { get; set; }
    public string Whatever { get; set; }
}

- 1 | Fred | { { AAA | xxx }, { BBB | yyy } }
- 2 | Bill | { { CCC | zzz } }

要:

public class FooProjection
{
    public int Id { get; set; }
    public string Name { get; set; }
    public PewPewName { get; set; }
    public PewPewWhatever { get; set; }
}

- 1 | Fred | AAA | xxx
- 1 | Fred | BBB | yyy
- 2 | Bill | CCC | zzz

2 个答案:

答案 0 :(得分:12)

纯Linq方法

您可以使用SelectMany()重载,它允许您指定在集合中的每个元素上调用的结果选择器:

  

将序列的每个元素投影到IEnumerable,展平   将序列生成一个序列,并调用结果选择器   对其中的每个元素起作用。

List<Foo> foos = new List<Foo>();
var fooProjections = foos.SelectMany(x => x.PewPews, (foo, pew) => new FooProjection() 
{ 
    Id = foo.Id, 
    Name = foo.Name,
    PewPewName = pew.Name,
    PewPewWhatever = pew.Whatever 
}).ToList();

这种方法最简洁,但需要一些时间来适应,特别是如果你没有和Linq一起工作很多。

修改

根据@ AS-CII的评论,可能更容易理解(这对维护代码库很重要)只使用循环和Select()的简单投影。如果有人在这个场景中遇到Linq问题,那么两个嵌套循环也会这样做。我将展示两者的完整性。

使用foreach循环和选择投影

只需迭代所有Foos,并为当前项目中的每个FooProjection创建一个新PewPew。将所有这些添加到范围内的fooProjections列表中。此方法使用Linq投影从每个PewPew映射到FooProjection,使用foreach循环中的foo

List<Foo> foos = new List<Foo>();
List<FooProjection> fooProjections = new List<FooProjection>();

foreach(var foo in foos)
{
    var someFooProjections = foo.PewPews.Select(x => new FooProjection() 
    { 
        Id = foo.Id, 
        Name = foo.Name, 
        PewPewName = x.Name, 
        PewPewWhatever = x.Whatever 
    });
    fooProjections.AddRange(someFooProjections);
}

使用两个嵌套的foreach循环

只需使用两个foreach循环,外部迭代在Foos上,内部覆盖当前foo中的PewPews集合 - 在FooProjection列表中添加新的fooProjections范围。这种方法根本没有使用Linq。

List<FooProjection> fooProjections = new List<FooProjection>();
foreach (var foo in foos)
    foreach (var pew in foo.PewPews)
    {
        fooProjections.Add(new FooProjection()
        {
            Id = foo.Id,
            Name = foo.Name,
            PewPewName = pew.Name,
            PewPewWhatever = pew.Whatever
        });
    }

答案 1 :(得分:5)

我发现多个from的查询表达式比调用SelectMany更容易编写。他们编译成同样的东西。

List<Foo> foos = GetFoos();

var projected = 
    from foo in foos
    from pewPew in foo.PewPews
    select new FooProjection
        { Id = foo.Id, 
          Name = foo.Name, 
          PewPewName = pewPew.Name, 
          PewPewWhatever = pewPew.Whatever };