Linq group by and count

c# entity-framework-6 linq sql

Question

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)

1
0
7/16/2014 2:06:25 PM

Accepted Answer

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

0
7/16/2014 3:12:38 PM

Popular Answer

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() });


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow