Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding AsSubQuery() causing other parts of the query to fail #53

Open
redwyre opened this issue Feb 11, 2024 · 1 comment
Open

Adding AsSubQuery() causing other parts of the query to fail #53

redwyre opened this issue Feb 11, 2024 · 1 comment

Comments

@redwyre
Copy link

redwyre commented Feb 11, 2024

I'm getting the error:

System.InvalidOperationException: 'The LINQ expression 'x1 => new ViewEntryPlayerDto{ 
    SteamId = x1.SteamPlayer.Id, 
    SteamName = x1.SteamPlayer.Name 
}
' could not be translated.  [...]

Here is what the debug expression looks like:

DbSet<Entry1>()
    .OrderByDescending(e => e.CattleMustered)
    .ThenBy(e => e.TimeTaken)
    .Select(e => new RankedEntry{ 
        Entry = e, 
        Rank = EF.Functions
            .RowNumber(EF.Functions
                .OrderByDescending(e.CattleMustered)
                .ThenBy(e.TimeTaken)) 
    }
    )
    .AsSubQuery()
    .OrderBy(re => re.Rank)
    .Select(x => new ViewEntryDto{ 
        Ranking = x.Rank, 
        Players = x.Entry.Players
            .Select(x1 => new ViewEntryPlayerDto{ 
                SteamId = x1.SteamPlayer.Id, 
                SteamName = x1.SteamPlayer.Name 
            }
            )
            .ToList(), 
        TimeTaken = x.Entry.TimeTaken, 
        CattleMustered = x.Entry.CattleMustered 
    }
    )

and the wrong query without it:

SELECT ROW_NUMBER() OVER(ORDER BY [e].[CattleMustered] DESC, [e].[TimeTaken]), [e].[Id], [t].[SteamId], [t].[SteamName], [t].[EntryId], [t].[PlayerNumber], [e].[TimeTaken], [e].[CattleMustered]
FROM [Entry1] AS [e]
LEFT JOIN (
    SELECT [p].[Id] AS [SteamId], [p].[Name] AS [SteamName], [e0].[EntryId], [e0].[PlayerNumber]
    FROM [EntryPlayer] AS [e0]
    INNER JOIN [Players] AS [p] ON [e0].[SteamPlayerId] = [p].[Id]
) AS [t] ON [e].[Id] = [t].[EntryId]
ORDER BY ROW_NUMBER() OVER(ORDER BY [e].[CattleMustered] DESC, [e].[TimeTaken]), [e].[Id], [t].[EntryId], [t].[PlayerNumber]

For setup I have opt.AddWindowFunctionsSupport().AddCustomQueryableMethodTranslatingExpressionVisitorFactory()

@PawelGerr
Copy link
Owner

Alas, EF Core doesn't translate everything. The root cause why you get the InvalidOperationException is the same as with following query that has nothing to do with RowNumber nor AsSubQuery:

// Entity + Distinct + Use of NavProp is currently not supported

DbSet<Entry1>()
    .Select(e => new RankedEntry { 
        Entry = e // <- "Entity" + ...
     })
    .Distinct()     // <- ... + "Distinct" + ...
    .Select(x => new ViewEntryDto{ 
        Entry = x.Entry, 
        Players = x.Entry.Players  // <- ... + "Use of NavProp"
            .Select(x1 => new ViewEntryPlayerDto{ 
                SteamId = x1.SteamPlayer.Id, 
                SteamName = x1.SteamPlayer.Name 
            })
            .ToList()
    })

If EF Core translates query above in the future then most likely AsSubQuery will work as well.

To make the issue more obvious you can try the same query without projection of the players.

DbSet<Entry1>()
    .Select(e => new RankedEntry { 
        Entry = e 
     })
    .Distinct() 
    .Select(x => new ViewEntryDto{ 
        Entry = x.Entry, 
        Players = x.Entry.Players
    })

You still doesn't get the players, but what's worse, you do not even get an exception!


As a workaround you can use Join/LeftJoin to get the players.
Something like

DbSet<Entry1>()
   // actually, the OrderByDescending+ThenBy shouldn't be necessary here
    .OrderByDescending(e => e.CattleMustered)
    .ThenBy(e => e.TimeTaken)
    .Select(e => new RankedEntry{ 
        Entry = e, 
        Rank = EF.Functions
            .RowNumber(EF.Functions
                .OrderByDescending(e.CattleMustered)
                .ThenBy(e.TimeTaken)) 
    })
    .AsSubQuery()
    .OrderBy(re => re.Rank)
    .LeftJoin( DbSet<Player>(), <join conditions using scalar properties only> ,
       x => new ViewEntryDto{ 
        Ranking = x.Left.Rank,  
        TimeTaken = x.Left.TimeTaken, 
        CattleMustered = x.Left.CattleMustered,
        Players = x.Right
            .Select(x1 => new ViewEntryPlayerDto{ 
                SteamId = x1.SteamPlayer.Id, 
                SteamName = x1.SteamPlayer.Name 
            })
            .ToList() 
    })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants