dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.66k stars 3.16k forks source link

ThenBy after select (with previous orderby) throw exception #34363

Open puschie286 opened 1 month ago

puschie286 commented 1 month ago

File a bug

Using ThenBy on ordered query where one entity was selected throws an exception.

If only one OrderBy is used (inner or outer), it works fine. If both OrderBy and ThenBy are done before Select, it works too.

https://dotnetfiddle.net/hiEFxJ

The goal is to (dynamically) join on multiple entities and order by properties of these entities. The join target only knows the source/base entity

Query code from example:

// part 1
var query = context.Set<Blog>()
    .Join( context.Set<Post>(), outer => new { Id = outer.BlogId }, inner => new { Id = inner.BlogId }, ( outer, inner ) => new { o = outer, i = inner } )
    .OrderBy( x => x.i.Title )
    .Select( x => x.o );
// part 2       
if( query is IOrderedQueryable<Blog> orderedQuery )
{
    query = orderedQuery.ThenBy( x => x.Url );
}

Include stack traces

Unhandled exception. System.ArgumentException: Expression of type 'System.Linq.IQueryable`1[Blog]' cannot be used for parameter of type 'System.Linq.IOrderedQueryable`1[Blog]' of method 'System.Linq.IOrderedQueryable`1[Blog] ThenBy[Blog,String](System.Linq.IOrderedQueryable`1[Blog], System.Linq.Expressions.Expression`1[System.Func`2[Blog,System.String]])' (Parameter 'arg0')
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1)
   at System.Linq.Queryable.ThenBy[TSource,TKey](IOrderedQueryable`1 source, Expression`1 keySelector)
   at Program.Main()

Include provider and version information

(might be different for the fiddle) EF Core version: ef 8.0.4 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: 8.0 Operating system: win10 IDE: rider

Expected SQL:

SELECT [b].[BlogId], [b].[Url]
FROM [Blogs] AS [b]
INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
ORDER BY [p].[Title], [b].[Url]
puschie286 commented 1 month ago

notice that checking for IOrderedQueryable is not enough. But how would you do this when query part 1 (50-53) and part 2 (55-58) doesnt know about each other ? - both have an IQueryable<Blog> as input and output