Reputation: 51
Pretty new in C# trying to Join two collections together, where the final result will provide all data from both collections. Right now the code returns only matched documents. Thank you.
//Collections IQueryable collection1 = database.GetCollection("MainData").AsQueryable(); IQueryable collection2 = database.GetCollection("SecondaryData").AsQueryable(); var result = collection2.Join(collection1, a => a.ID, b => b.ID, (a, b) => new { a, b }) .ToList() .Select(s => new ViewModel.Customer() { ID = s.b.ID, FirstName = s.b.FirstName LastName = s.b.LastName }).ToList(); return result;
Upvotes: 2
Views: 6474
Reputation: 30502
Ok, so you have two queries to fetch sequences of different types, let's say ClassA
and ClassB
. Both types have a property Id
, and you want some kind of join on this Id.
... where the final result will provide all data from both collections
It's good to realize there are various types of Joins. The join you coded is the most simple join, quite often called an inner join
. Only elements that have matching Ids are in the resulting sequence. So if you've got a ClassA with Id = 3, but there is no ClassB with this Id, then it won't be in your result.
IQueryable<ClassA> itemsA = ...
IQueryable<ClassB> itemsB = ...
var innerJoinResult = itemsA.Join(itemsB, // inner join A and B
itemA => itemA.Id, // from each itemA take the Id
itemB => itemB.Id, // from each itemB take the Id
(itemA, itemB) => new // when they match make a new object
{ // where you only select the properties you want
NameA = itemA.Name,
NameB = itemB.Name,
BirthdayA = itemA.Birthday,
...
});
If you also want the items without matching Id, so all itemsA without a matching itemB.Id and all itemsB without a matching itemA.Id, you'll have to do a full outer join. This seems to be what you meant when you wrote:
... where the final result will provide all data from both collections
LINQ does not have this functionality as a standard, but you can write an extension method for it.
See this excellent 2nd answer in stackoverflow for a LINQ extension function for a full outer join.
Also see Extension Methods Demystified
Upvotes: 4
Reputation: 4812
You can do this by also doing a reverse join from collection1 onto collection2 and then UNION
on the results.
var resultSet1 = collection2.Join(collection1, a => a.ID, b => b.ID, (a, b) => new { a, b })
.ToList()
.Select(s => new ViewModel.Customer()
{
ID = s.b.ID,
FirstName = s.b.FirstName,
LastName = s.b.LastName
}).ToList();
var resultSet2 = collection1.Join(collection2, a => a.ID, b => b.ID, (a, b) => new { a, b })
.ToList()
.Select(s => new ViewModel.Customer()
{
ID = s.b.ID,
FirstName = s.b.FirstName,
LastName = s.b.LastName
}).ToList();
return resultSet1.Union(resultSet2);
Upvotes: 1
Reputation: 995
You could use
Concat
which will return the items from the first collection followed by the items from the second collection:
var combined = collection1.Concat(collection2);
Or you could use
Union
which will return distinct values from both collections:
var combined = collection1.Union(collection2);
Upvotes: 4