14

I've looked at various questions on SO and other sites, and this appears to be the correct syntax to perform a JOIN in LINQ, however it's just not working:

var stages = (from stage in entityManager.TPM_TASKSTAGE select stage);
var results = (from task in pv.TPM_TASK
               join st in stages on st.STAGEID equals task.STAGEID
               where task.TASKTYPE == "Solution"
               select new SolutionTask());

Ignore, for now, the fact that I don't actually select anything of interest, but I'd like to have access to the st.NAME property on each row of TPM_TASK. The two tables are linked by STAGEID. I get the compiler error:

The name 'st' is not in scope on the left side of 'equals'. Consider swapping the expressions on either side of 'equals'.

In the LINQ join expression, both st and task have red squigglies. Please tell me I'm doing something dumb.

Community
  • 1
  • 1
Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • 1
    Did you try following the exact instructions in the error message? ("Consider swapping the expressions on either side of 'equals'") – Jon Skeet Apr 08 '13 at 21:41
  • @JonSkeet - That was actually the *first* thing I tried, however my expression was `task.STAGEID == st.STAGEID`. This yields a similar compiler error (suggesting I swap the expressions). So I did, and also switched to `equals` thinking that might make a difference. I did not try `task.STAGEID equals st.STAGEID` which is the valid combination! Sigh. – Mike Christensen Apr 08 '13 at 21:45
  • When you had `task.STAGEID == st.STAGEID` you wouldn't have got the same error message, because your join would have been *completely* invalid at that point. – Jon Skeet Apr 08 '13 at 21:46
  • @JonSkeet - You are right about that, however Visual Studio seems to *cache* that error message temporarily until you do a full compile. It seems the IDE's error checking doesn't catch the `==` on the fly, but does catch the fact that it cannot resolve the context of `st`. My fault for not doing a compile to see the *real* error messages. – Mike Christensen Apr 08 '13 at 21:49

1 Answers1

19

Key selector from outer sequence should go first. Outer sequence in your case is pv.TPM_TASK. So, you should join on task.STAGEID equals st.STAGEID

var stages = (from stage in entityManager.TPM_TASKSTAGE select stage);
var results = (from task in pv.TPM_TASK
               join st in stages on task.STAGEID equals st.STAGEID // here
               where task.TASKTYPE == "Solution"
               select new SolutionTask());
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • 1
    Picky compiler. Thanks so much! – Mike Christensen Apr 08 '13 at 21:41
  • 1
    @MikeChristensen: It's really not a matter of being picky. The two sides of `equals` have completely different scopes: the left side has no knowledge of `st`, and the right side has no knowledge of `task`. For this sort of thing, it's useful to think about what the query expression syntax really means. See http://msmvps.com/blogs/jon_skeet/archive/2011/01/28/reimplementing-linq-to-objects-part-41-how-query-expressions-work.aspx for more details. – Jon Skeet Apr 08 '13 at 21:48
  • @JonSkeet - Thanks for the info! I'm kinda a LINQ novice, and get thrown off easily when it comes to the more complicated things like joins. I figured they worked similar to a SQL JOIN, where the order of operands doesn't matter. – Mike Christensen Apr 08 '13 at 21:53
  • 1
    @JonSkeet's link is broken. Use this https://codeblog.jonskeet.uk/2011/01/28/reimplementing-linq-to-objects-part-41-how-query-expressions-work/ – Rajeev Feb 01 '20 at 14:02