I see what's the problem: you join the same element twice using the exact same lambda. (ProductSubCategory).
The problem is that our linq provider currently has a known issue where it assigns aliases to anonymous type members to be able to refer to the real source later on, but in the query there can be multiple times the same anonymous type used while meaning the same thing. Adding the 'let' statement makes the lambda different (the anonymous type is different) so this problem isn't occuring.
Same problem occurs with this query:
LinqMetaData metaData = new LinqMetaData(adapter);
var q = from o in metaData.Order
join cust in metaData.Customer on o.CustomerId equals cust.CustomerId
where o.OrderId == 10261
select new
{
CountOfDiscontinuedProducts = Convert.ToInt32(o.OrderDetails.Count(od => od.Product.Discontinued == true)),
CountOfNotDiscontinuedProducts = Convert.ToInt32(o.OrderDetails.Count(od => od.Product.Discontinued == false)),
};
It's a tough problem though, as linq is sequenced based and wraps original references into anonymous types, like in a join, so a member of an anonymous type is one side of a join, however in the end query, the side of the join is reachable directly, not through a set of properties on a derived table (nested select). This leads to alias - source links which cause problems if a member of a given anonymous type T is re-used by the compiler. When we wrote the linq provider back in 2008 we didn't anticipate on this, and we found this out more than a year later... It does require a big change inside the linq provider though hence the reason we didn't fix it today. The problem also doesn't occur that often, however that's not something you can use of course.
For v3 we have planned to fix this (which will happen in the next couple of weeks), and if possible, we'll backport the fix to v2.6's linq provider. The problem is that it is rather hard to do, as a 'member' isn't enough apparently to obtain the alias of the real source what it represents, but that means that context info is required, however at multiple places inside a linq expression tree, there's no other context information available. We do have a scope visitor inside the linq provider which might help in this, but it's not said if we can fix it inside our linq provider.
I know the workaround is lame, but it's all we can offer you at this point. Sorry for this lame inconvenience.