简体   繁体   中英

Linq group by and count

I'm trying to understand how groupy by and count works with linq but i can't get how to do what i want.

I have this table:

ASSET:
Id, Code, Name, ParentId

the ParentId is null if its the root, and contains the parent id if the asset is linked to another asset

I'd like to have for each root parents the Id and the number of children

this is the query i used:

select father.Id, father.Code, COUNT(children.Id) As NumberOfChildren 
from Asset father 
left join Asset children on(father.Id = children.ParentId) 
where father.ParentId IS NULL 
group by father.Id, father.Code

this is the linq query i do

var query = from father in this.assetService.GetAll() 
                        join children in this.assetService.GetAll() 
                        on father.Id equals children.ParentId into Children 
                        from children in Children.DefaultIfEmpty() 
                        where father.ParentId.Value == null 
                        group father by new { id = father.Id, code = father.Code } into gf 
                        select new { id = gf.Key.id, count = gf.Count() };

but entity generates that query:

SELECT 
    1 AS [C1], 
    [GroupBy1].[K1] AS [Id], 
    [GroupBy1].[A1] AS [C2] 
    FROM ( SELECT 
        [Extent1].[Id] AS [K1], 
        [Extent1].[Code] AS [K2], 
        COUNT(1) AS [A1] 
        FROM  [dbo].[Asset] AS [Extent1] 
        LEFT OUTER JOIN [dbo].[Asset] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ParentId] 
        WHERE [Extent1].[ParentId] IS NULL 
        GROUP BY [Extent1].[Id], [Extent1].[Code] 
    )  AS [GroupBy1]

the issue comes from the COUNT(1) , how can i tell thats its supposed to be COUNT(children.Id)

You could try something like this:

// Get all the assets in a list.
var assets = this.assetService.GetAll().ToList();

// Get the parents.
var parents = (from asset in assets
               where asset.ParentId == null);

// Remove parents from the original list.
var children = assets.RemoveAll(x => parents.Contains(x));

// Group the children by their parentId
var result = children.GroupBy(x => x.ParentId)
                     .Select(x => new { ParentId = x.Key, Count = x.Count() });

Since you want to deal with the NULL values in children.Id , you'll need a way to count them when you are selecting your final object. To do this, you would group into a new object that you could query against in order to get the right count. Here's the modified query object you're looking for:

var query = from father in this.assetService.GetAll() 
                        join children in this.assetService.GetAll() 
                        on father.Id equals children.ParentId into Children 
                        from children in Children.DefaultIfEmpty() 
                        where father.ParentId.Value == null 
                        group new { father = father, childExists = (children != null) } by new { id = father.Id, code = father.Code } into gf 
                        select new { id = gf.Key.id, count = gf.Count(o => o.childExists) };

I used the following C# fiddle to test it, and it correctly returns 0 records if a parent has no children.

https://dotnetfiddle.net/gyqpef

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM