Your identifiers are not very meaningful. You did this probably for the question, but it makes it fairly difficult to grasp the relation between TableA
and TableB
.
It seems to me that there is a one-to-many relation between TableA and TableB: every row from TableB has zero or more rows from TableA; every row from TableA "belongs" to exactly one row from TableB, namely the row that foreign key IntId
refers to.
From every TableB row with its TableA items
, you want to fetch TableB.IntId
, TableB.CreateDate
and the largest TableA.TwoId
of all TableA rows that belong to this TableB.
Whenever you need to fetch "items with their sub-items" from a one-to-many relation, like Schools with their Students, Customer with their Orders, or "TableB rows with their TableA rows", consider to use one of the overloads of Queryable.GroupJoin.
Because I don't just want some special results, not just "TableB rows with their TableA rows", I use the overload that has a parameter resultSelector:
IQueryable<TableARow> tableA = ...
IQueryable<TableBRow> tableB = ...
var result = tableB.GroupJoin(tableA, // GroupJoin TableB with TableA
tableBRow => tableBRow.IntId, // from every row in tableB take the IntId
tableARow => tableARow.IntId, // from every row in tableA take the foreign key
// parameter resultSelector: from every row in tableB, with its zero or more
// matching rows from tableA, make one new object:
(tableBRow, matchingTableARows) => new
{
IntId = tableBRow.IntId,
CreateDate = tableBRow.CreateDate,
LargestTwoId = matchingTableARows.Select(tableARow => tableARow.TwoId).Max(),
})
In words: from every row from tableB, take the value of IntId. Then find all rows from tableA that have a matching IntId value. From every tableB row, with all its zero or more tableA rows, create one new object with the following three properties:
- IntId is the IntId of the tableBRow (which, by the ways equals the IntId of all matching tableARows)
- CreateDate is the CreateDate of the tableBRow
- LargestTwoId is calculated as follows:
from every tableARow that has a value for IntId that matches the tableBRow, take only the value of property TwoId. From all these TwoId values take the largest one.
I chose to use Max
instead of OrderByDescending
, because it is a waste of processing power to Order all elements, if you will be using only the first one.
There is a small flaw with this: Max
only works if there is at least one element. If you think there are some tableBRows that have no matching tableARow, then this won't work.
LargestTwoId = matchingTableARows.Select(tableARow => tableARow.TwoId)
.OrderByDescending(twoId => twoId)
.FirstOrDefault(),
or:
LargestTwoId = matchingTableARows.Any() ?
matchingTableARows.Select(tableARow => tableARow.TwoId).Max() :
null,