LINQ select after grouping
I'm trying to return a result set from a grouped query and I can't get the select right. In LinqPad the cursor jumps to "ItemID" in Grouped.Key.ItemID with the error:
开发者_如何学Go'int' does not contain a definition for 'ItemID' and no extension method 'ItemID' accepting a first argument of type 'int' could be found
Here's the query:
from B in Bids
join I in Items on B.ItemID equals I.ItemID
group new {B, I} by I.ItemID into Grouped
select new {
ItemID = Grouped.Key.ItemID,
ItemName = Grouped.Key.ItemName,
Bids = Grouped.Key.B
}
I would like the return set to have records comprised of the ItemID, ItemName and all of the associated Bid records.
Thanks very much,
BK
The Grouped.Key refers to the field(s) that you specied in the grouped by x clause. As a result in your query, the Key = I.ItemID.
In your example, instead of thinking from the SQL perspective where you have to flatten out heirarchies, embrace the OO nature of LINQ and object graphs. Adapting your example a bit and setting LINQPad to use C# Statements, I think you will end up with more of what you are looking for. Note: The Dump() extension method is specific to LINQPad to output the results and shows the resulting heirarchy.
var bids = new [] { new { ItemID = 1, BidValue = 30 } , new {ItemID=1, BidValue=45}};
var items = new [] { new { ItemID = 1, ItemName = "x" }, new {ItemID = 2, ItemName="y"} };
var query = from i in items
select new
{
i.ItemID,
i.ItemName,
Bids = from b in bids
where b.ItemID == i.ItemID
select b
};
query.Dump();
That being said, your categories indicate LINQ to SQL. If your model is in LINQ to SQL or EF, you may be able to do this even easier by using the mapped associations:
var query = from i in dc.Items
select new
{
i.ItemID,
i.ItemName,
i.Bids
};
query.Dump();
That says exactly what is written. Groupped.Key will contain I.ItemID, but not the whole I. So you can't write Groupped.Key.ItemID
.
Consider:
from B in new [] { new { ItemID = 1, BidValue = 30 } }
join I in new [] { new { ItemID = 1, ItemName = "x" } } on B.ItemID equals I.ItemID
group new { B, I } by I into Groupped
select new {
ItemID = Groupped.Key.ItemID,
ItemName = Groupped.Key.ItemName,
Bids = (from g in Groupped select g.B).ToList()
}
Well, assuming you have foreign keys setup in the database from bid -> item there is no need for all this joining an grouping.
Your items will already have a collection of bids in them.
So you can do things like:
var x = db.Items.Single(i=>ItemId == 1); // get one item
foreach (bid b in x.Bids) // iterate through all the bids
{}
If you really want to have them in an anonymous type, this will do:
from i in db.items
select new { i.ItemID, i.ItemName, i.Bids }
That is the beauty of Linq2Sql. Try to let go of writing SQL in Linq but instead use the more object oriented approach.
In this groupby, ItemID is the Key. ItemID does not have a B property.
group new {B, I} by I.ItemID into Grouped
Here's an improved version of your query which accesses the group properly.
from b in Bids
join i in Items on b.ItemID equals i.ItemID
group b by i into groupedBids
select new
{
Item = i,
Bids = groupedBids
};
Here's a version that uses GroupJoin to do the same thing.
from i in Items
join b in Bids on i.ItemID equals b.ItemID into groupedBids
select new
{
Item = i,
Bids = groupedBids
};
Here's a version that does the join in the database and the group locally. You might do something like this since LinqToSql must re-query by the key of a group to get each group's elements (known as the n+1 problem with groupby).
from x in
(
from i in Items
join b in Bids on i.ItemID equals b.ItemID
select new {Item = i, Bid = b}
).ToList()
group x.b by x.i into groupedBids
select new
{
Item = groupedBids.Key,
Bids = groupedBids
};
精彩评论