How can I use LINQ to project this parent and child object model into one flat object?

I am trying to smooth a simple class with a parent + child array into one class.

From:

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 } } 

To:

 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 
+7
source share
2 answers

Pure Linq Approach

You can use the SelectMany() overload, which allows you to specify a result selector that is called for each item in the collection:

Projects each element of a sequence onto IEnumerable, aligns the resulting sequences into one sequence and calls the function result selector for each element in it.

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

This approach is the most concise, but takes some time to get used to, especially if you have not worked with Linq a lot.

Edit:

As with the AS-CII comment, it would be easier to understand (and this is important for maintaining the code base) just use a loop and simple projection using Select() . If anyone has problems with Linq in this scenario at all, two nested loops will also do. I will show how for completeness.

Using foreach loop and Select projection

Just iterate over all the Foos and create a new FooProjection for each PewPew in the current item. Add all of them to the fooProjections list, which is in scope. This approach uses the Linq projection to display from each PewPew to a FooProjection , using foo from the foreach loop.

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

Using two nested foreach loops

Just use two foreach loops, an outer iteration over the Foos, an inner iteration over the PewPews collection in the current foo - add the new FooProjection to the fooProjections list, which is in scope. This approach does not use Linq at all.

 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 }); } 
+13
source

I find query expressions with a few from much easier to write than SelectMany calls. They compile into the same thing.

 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 }; 
+6
source

Source: https://habr.com/ru/post/896839/


All Articles