Efcore: Column 'x' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.'

Created on 25 May 2020  路  5Comments  路  Source: dotnet/efcore

I use latest EF core, time of writing, 3.1.4

This is the query

var foo = await db.Set<Party>()
    .Where(p => p.CreditAccountType.HasValue)
    .Select(p => new
    {
        p,
        ActiveAndOpenAgreements = p.AutogiroAgreements.Where(agp => agp.IsActive && agp.Agreement.State == AutogiroAgreementState.Accepted)
    })
    .Select(info => new 
    {
        info.p.PartyName,
        info.p.PartyNumber,
        HasActiveAgreements = info.ActiveAndOpenAgreements.Any(),
        HasMultipleSystems = info.ActiveAndOpenAgreements.GroupBy(agp => agp.Agreement.ExternalSystem).Count() > 1
    })
    .ToListAsync();

I have tried doing this both in one select and with two selects as above, same outcome.
The problem is that I do a GroupBy to find out if we got duplicate rows. When executing this query I get

'Column 'dbo.AutogiroAgreementPayerParty.AutogiroAgreementId' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.'

Projected SQL looks like

SELECT [p].[PartyName], [p].[PartyNumber], CASE
    WHEN EXISTS (
        SELECT 1
        FROM [dbo].[AutogiroAgreementPayerParty] AS [a]
        INNER JOIN (
            SELECT [a0].[Id], [a0].[BgcMessage], [a0].[CreatedBy], [a0].[CreatedUTC], [a0].[ExternalId], [a0].[ExternalSystemId], [a0].[LegacyId], [a0].[PayerBankAccountNumber], [a0].[PayerClearingNumber], [a0].[ReceiverAccountId], [a0].[AutogiroAgreementStateId], [a0].[UpdatedBy], [a0].[UpdatedUTC], [a1].[Id] AS [Id0], [a1].[AccountName], [a1].[AccountNumber], [a1].[AccountTypeId], [a1].[BgcCustomerId], [a1].[IsPbfAccount], [a1].[OwnerPartyId], [a1].[RelatedAccountId], [a2].[Id] AS [Id1], [a2].[AccountName] AS [AccountName0], [a2].[AccountNumber] AS [AccountNumber0], [a2].[AccountTypeId] AS [AccountTypeId0], [a2].[BgcCustomerId] AS [BgcCustomerId0], [a2].[IsPbfAccount] AS [IsPbfAccount0], [a2].[OwnerPartyId] AS [OwnerPartyId0], [a2].[RelatedAccountId] AS [RelatedAccountId0], [b].[Id] AS [Id2], [b].[BrokerPartyId], [b].[CustomerName], [b].[CustomerNumber], [b].[ExternalSystemId] AS [ExternalSystemId0]
            FROM [dbo].[AutogiroAgreement] AS [a0]
            INNER JOIN [dbo].[Account] AS [a1] ON [a0].[ReceiverAccountId] = [a1].[Id]
            LEFT JOIN [dbo].[Account] AS [a2] ON [a1].[RelatedAccountId] = [a2].[Id]
            LEFT JOIN [dbo].[BgcCustomer] AS [b] ON [a2].[BgcCustomerId] = [b].[Id]
            WHERE (@__ef_filter__p_0 = CAST(1 AS bit)) OR [b].[BrokerPartyId] IS NULL
        ) AS [t] ON [a].[AutogiroAgreementId] = [t].[Id]
        WHERE ([p].[Id] = [a].[PayerPartyId]) AND (([a].[IsActive] = CAST(1 AS bit)) AND ([t].[AutogiroAgreementStateId] = 1))) THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END AS [HasActiveAgreements], CASE
    WHEN (
        SELECT COUNT(*)
        FROM (
            SELECT [a3].[AutogiroAgreementId], [a3].[PayerPartyId], [a3].[IsActive], [a3].[IsOwner]
            FROM [dbo].[AutogiroAgreementPayerParty] AS [a3]
            INNER JOIN (
                SELECT [a4].[Id], [a4].[BgcMessage], [a4].[CreatedBy], [a4].[CreatedUTC], [a4].[ExternalId], [a4].[ExternalSystemId], [a4].[LegacyId], [a4].[PayerBankAccountNumber], [a4].[PayerClearingNumber], [a4].[ReceiverAccountId], [a4].[AutogiroAgreementStateId], [a4].[UpdatedBy], [a4].[UpdatedUTC], [a5].[Id] AS [Id0], [a5].[AccountName], [a5].[AccountNumber], [a5].[AccountTypeId], [a5].[BgcCustomerId], [a5].[IsPbfAccount], [a5].[OwnerPartyId], [a5].[RelatedAccountId], [a6].[Id] AS [Id1], [a6].[AccountName] AS [AccountName0], [a6].[AccountNumber] AS [AccountNumber0], [a6].[AccountTypeId] AS [AccountTypeId0], [a6].[BgcCustomerId] AS [BgcCustomerId0], [a6].[IsPbfAccount] AS [IsPbfAccount0], [a6].[OwnerPartyId] AS [OwnerPartyId0], [a6].[RelatedAccountId] AS [RelatedAccountId0], [b0].[Id] AS [Id2], [b0].[BrokerPartyId], [b0].[CustomerName], [b0].[CustomerNumber], [b0].[ExternalSystemId] AS [ExternalSystemId0]
                FROM [dbo].[AutogiroAgreement] AS [a4]
                INNER JOIN [dbo].[Account] AS [a5] ON [a4].[ReceiverAccountId] = [a5].[Id]
                LEFT JOIN [dbo].[Account] AS [a6] ON [a5].[RelatedAccountId] = [a6].[Id]
                LEFT JOIN [dbo].[BgcCustomer] AS [b0] ON [a6].[BgcCustomerId] = [b0].[Id]
                WHERE (@__ef_filter__p_0 = CAST(1 AS bit)) OR [b0].[BrokerPartyId] IS NULL
            ) AS [t0] ON [a3].[AutogiroAgreementId] = [t0].[Id]
            WHERE ([p].[Id] = [a3].[PayerPartyId]) AND (([a3].[IsActive] = CAST(1 AS bit)) AND ([t0].[AutogiroAgreementStateId] = 1))
            GROUP BY [t0].[ExternalSystemId]
        ) AS [t1]) > 1 THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END AS [HasMultipleSystems]
FROM [dbo].[Party] AS [p]
WHERE [p].[CreditAccountTypeId] IS NOT NULL
area-query customer-reported type-bug

All 5 comments

GroupBy support is very limited in EF Core and have found myself to try different workarounds whenever I would have liked a simple GroupBy.

Perhaps it would be possible to get around it by using something like (untested)

HasMultipleSystems = info.ActiveAndOpenAgreements.Select(agp => agp.Agreement.ExternalSystemId).Distinct().Count() > 1

or resolve again from db root (pseudocode since I do not know your table layout)

HasMultipleSystems = db.Set<ExternalSystem>().Where(s => info.ActiveAndOpenAgreements.Contains(agp => agp.Agreement.ExternalSystemId == s.Id)).Count() > 1

Thats sad to hear, this used to work just fime in Ef 6. Hope they are working on getting it supported.

Edit: will try the distinct approuch

@joakimriedel Distinct actually did work, which is fine in this case. But maybe you want to operate on that data in a grouped by fashion than distinct will not cut it. Thanks for intput!

edit: I played aroudn some more, on another data entity this time, same idea though, this works

db.Set<DataAccess.Entities.dbo.Party>()
                        .Select(p => new
                        {
                            p.PartyName,
                            p.PartyNumber,
                            HasDuplicates = p
                                .CreditAccounts
                                .GroupBy(ca => ca.AccountNumber).Any(grp => grp.Count() > 1)
                        })
                        .ToListAsync();

This does not

db.Set<DataAccess.Entities.dbo.Party>()
                        .Select(p => new
                        {
                            p.PartyName,
                            p.PartyNumber,
                            Duplicates = p
                                .CreditAccounts
                                .GroupBy(ca => ca.AccountNumber).Where(grp => grp.Count() > 1)
                        })
                        .ToListAsync();

Gives Client side GroupBy is not supported.

Sensitive bugger :D

@AndersMalmgren happy to hear that, let's hope for a more capable query processor in the near future

@joakimriedel Yeah agreed. I updated above with some more interesting findings :D

Was this page helpful?
0 / 5 - 0 ratings