Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Joining parent and child collection in LINQ for a single merged output

Tags:

c#

linq

I have a collection of items which each contain a secondary collection. I need to generate a list of new items based off the total set of secondary items. Eg if you have a list of dogs and each dog has a list of friends, I need a total list of all dog friends for all dogs.

Normally I would do this with SelectMany but the difficulty here is my secondary objects do not contain a reference back to the parent object, and the new list needs to contain fields from both secondary and parent objects. ie as below

var dogs = List<Dog>
var newList = dogs.SelectMany(i => i.DogFriends).Select(dogFriend => new NewObject
            {
                fieldOne = dog.propertyOne,
                fieldTwo = dog.propertyTwo
                fieldThree = dogFriend.propertyOne
            });

In the above, I have no reference to dog however, so I cannot select those.

What I'm looking for is a way to do a join on the two tables as in SQL, so you can select values from both objects. But I want the total values to match the total number of child objects. Ie if you have 3 dogs with 3 friends each, the final list will have 9 objects.

How can I achieve this with LINQ?

like image 424
NZJames Avatar asked Mar 09 '16 11:03

NZJames


People also ask

Can we use join in LINQ C#?

In a LINQ query expression, join operations are performed on object collections. Object collections cannot be "joined" in exactly the same way as two relational tables. In LINQ, explicit join clauses are only required when two source sequences are not tied by any relationship.

Which join is valid in LINQ?

In LINQ, an inner join is used to serve a result which contains only those elements from the first data source that appears only one time in the second data source. And if an element of the first data source does not have matching elements, then it will not appear in the result data set.

Can I join a table to a list using LINQ?

You probably found out that you can't join an Entity Framework LINQ query with a local list of entity objects, because it can't be translated into SQL. I would preselect the database data on the account numbers only and then join in memory.

What is grouped join in LINQ with example?

Grouped Joins in LINQ. The group join is useful for producing hierarchical data structures. It pairs each element from the first collection with a set of correlated elements from the second collection. This definiation will become more clear with the following examples.

When LINQ query is executed?

When the basic initial part of LINQ query is executed, in other words: As we can see for each parent Id of the Parent object a collection of Child objects with matching ParentId is generated, so now all that is left is to play with this resulting collection based on the rules provided. Here is the complete query:

What is the structure of the classes representing a parent-child relationship?

The structure of the classes representing a Parent-Child relationship is shown below. Each Department has many Employees, but one Employee belongs to only one Department Here are some common Operations on a Hierarchical Parent-Child List.


2 Answers

Indeed .SelectMany(...) is the answer. Another usage is:

var data = dogs
    .SelectMany(d => d.DogFriends.Select(df => new { d, df })
    .Select(x =>
        // Now you can use both d and df
        new NewObject {
            fieldOne = x.d.propertyOne,
            fieldTwo = x.d.propertyTwo
            fieldThree = x.df.propertyOne
        }
    )
    .ToArray();

Even simpler is to use the query LINQ notation. This basically translates to the above at compile time.

var data = from d in dogs
           from df in d.DogFriends
           select new NewObject {
               fieldOne = d.propertyOne,
               fieldTwo = d.propertyTwo
               fieldThree = df.propertyOne
           }
like image 113
Maarten Avatar answered Oct 05 '22 22:10

Maarten


Use .SelectMany with the resultSelector overload

var query = petOwners.SelectMany(
                petOwner => petOwner.Pets, 
                (petOwner, petName) => new { petOwner, petName }
            )
like image 20
xumix Avatar answered Oct 05 '22 22:10

xumix