So when I group by, it seems I have to use the 'into' keyword which I
guess does some sort of projection?
There are two pure projection operators - Select
and SelectMany
.
Now I'm not sure how to reference j1.Username, j2.points now?
You have groups, which contain j1 entities only. And each group is a collection of j1 entities. You can aggregate results. But there is no single j1 entity, which you can get Username of. Thus you have groups of j1, you can't access j2 or j3. Your joins used only to filter users by points and addresses. After that you continued to query only users.
I see there is a 'Key' property but that doesn't let me navigate to
the columns.
Key property is a key of each group. In your case it will be CountryCode, which is same for all users in group.
Here is query which returns user name, address, and total points. How it works? First you join user and address with simple join. But you should project results into anonymous object which contain both user and answer. Otherwise answer will be 'lost' from scope, just as in your original query. So far so good - we have both user and answer. Now we need total points. For this GroupJoin is used - its not just correlates user-address pair with points, but also groups results (i.e. points) into points
group. Now you have all data accessible - user and address are in ua
object, and points related to user are in points
group. You can calculate totals:
from u in context.users
join a in context.addresses on u.UserId equals a.UserId
select new { u, a } into ua
join p in context.points on ua.u.UserId equals p.UserId into points
select new
{
ua.u.Username,
ua.u.CountryCode, // need for grouping by country
ua.a.address1,
Points = points.Sum()
}
// last grouping by country. You can omit it
into x
group x by x.CountryCode into g
select g;
BTW why not to use u, p and a variables for user, point and address? Why j1, j2, j3?