score:14
I am trying to understand why this linq does not compile
The key to understanding is to read the section of the specification on how queries are lowered into normal code.
Let's start with your query:
from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId into ps
select new Payment {
FundId = fundInvoices.Key.FundId, // ERROR here
Value = ps.Sum(p => p.Amount)
}
OK, step one. The rule in the spec is:
A query expression with a continuation
from … into x …
is translated intofrom x in ( from … ) …
Your query is now
from ps in (
from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId)
select new Payment {
FundId = fundInvoices.Key.FundId, // ERROR here
Value = ps.Sum(p => p.Amount)
}
And now it should be clear why fundInvoices
is not in scope in the select clause. fundInvoices
is a range variable of a completely different query.
But in case that is not clear, let's keep going. The next rule is:
A query expression of the form
from x in e select v
is translated into( e ) . Select ( x => v )
Your query is now
((from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
Now we can translate the inner query:
A query expression with a second from clause followed by something other than a select clause
from x1 in e1 from x2 in e2 …
is translated intofrom * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } ) …
The *
is a "transparent identifier" and we'll see what it means in a minute.
Your query is now
((from * in (paidfundInvoices).SelectMany(
fundInvoices => fundInvoices.Value,
(fundInvoices, p) => new {fundInvoices, p})
group p by p.VendorId))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
Final rule:
A query expression of the form
from x in e group v by k
is translated into( e ) . GroupBy ( x => k , x => v )
So that's
((((paidfundInvoices).SelectMany(
fundInvoices => fundInvoices.Value,
(fundInvoices, p) => new {fundInvoices, p}))
.GroupBy(* => p.VendorId, * => p)))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
The *
means "bring the pair of members of the anonymous type selected in the select-many into scope. Desugar that and remove the unnecessary parens and we have the final form of the query:
paidfundInvoices
.SelectMany(
fundInvoices => fundInvoices.Value,
(fundInvoices, p) => new {fundInvoices, p})
.GroupBy(pair => pair.p.VendorId, pair => pair.p)))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
And now it should be very clear why fundInvoices
is not in scope in the continuation. It would be in scope in the GroupBy
thanks to transparent identifier desugaring, but it is not at all in scope in the Select
.
More generally: in LINQ scopes generally flow from declarations on the left to usages on the right, but there are some exceptions: an into
removes range variables from scope, not all range variables are in scope at all places in a join
clause, and so on. Read the spec for more details.
score:1
Once you do the group
into
you can no longer access the original from
variables. If you need access, put it in the group:
from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group new { fundInvoices, p } by p.VendorId into ps
select new Payment
{
FundId = ps.fundInvoices.FundId,
Value = ps.Sum(p => p.Amount)
}
Source: stackoverflow.com
Related Articles
- Multiple linq "from" and variables visibility
- creating Linq to sqlite dbml from DbLinq source code
- how to remove objects from list by multiple variables using linq
- c# Linq or code to extract groups from a single list of source data
- Select Multiple Fields from List in Linq
- LINQ Join with Multiple From Clauses
- Creating a LINQ select from multiple tables
- How to select multiple values from a Dictionary using Linq as simple as possible
- How do I remove items from generic list, based on multiple conditions and using linq
- Enumerable.Empty<T>().AsQueryable(); This method supports the LINQ to Entities infrastructure and is not intended to be used directly from your code
- Does this LINQ code perform multiple lookups on the original data?
- How to understand the following C# linq code of implementing the algorithm to return all combinations of k elements from n
- LINQ - SelectMany from multiple properties in same object
- LINQ to SQL: Complicated query with aggregate data for a report from multiple tables for an ordering system
- C# multiple variables in lambda expression inside LinQ query
- How to pass LinQ Expressions from F# to C# code
- How to reuse a linq expression for 'Where' when using multiple source tables
- How to consolidate results from multiple IEnumerable<T> using LINQ
- Using LINQ to delete an element from a ObservableCollection Source
- How does linq actually execute the code to retrieve data from the data source?
- LINQ Source Code Available
- multiple orderby in this linq code
- Linq multiple join conditions using extra variables
- Linq query to select single string from multiple List<string>
- Creating multiple results from Linq query
- Is there a bug in this code from 101 LINQ Samples on MSDN? (Update: Fixed)
- Returning multiple streams from LINQ query
- Select data from multiple unrelated tables with LINQ to Entity Framework
- How to select multiple columns from dataset into a string list with LinQ
- LINQ select one bool from condition over multiple rows
- Sorting a `List<object>` by object properties
- Linq with transaction
- What advantages and drawbacks does Enumerable.SequenceEqual(list1, list2) has against list1.All(list2.Contains)?
- cannot get related table with Include in edmx and LinQ
- Using an Expression in a compiler-generated expression tree
- LINQ Duplicate (un)tagging method
- ASP.NET MVC2 Application showing Error in View
- Algorithm for comparing chars in strings
- LINQ query for an aggregate count with a recursive relationship
- linq grouping ID base and insert common data into new Array
- Linq progressive state based query
- Calculate a percentage column in controller for use in view
- Is it possible to use Linq and lambdas without including a System.Linq namespace?
- Select all records of a datatable with duplicate values
- Video Sitemap colon in name using LINQ to XML
- Narrowing LINQ query to one column
- Custom Query won't pass to view through viewmodel
- Linq with Different Where clauses and GroupBy
- Recursively iterate through subdirectories and add directory to a list, if it contains any file with a specific ending
- Trying to parse XML tree with Linq to XML (C#)