JonPSmith / EfCoreinAction-SecondEdition

Supporting repo to go with book "Entity Framework Core in Action", second edition

Home Page:https://bit.ly/EfCoreBook2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Test "TestThenIncludeSortSingle" is faling

Juansero29 opened this issue · comments

I just cloned the repo and the first thing I did was executing all test. There is a single test failing called "TestThenIncludeSortSingle".

Here's the exception it is throwing:

Message: 
    System.InvalidOperationException : The expression 'bookAuthor.AsQueryable().OrderBy(y => y.Author.Name)' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty'). Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations. For more information on including related data, see http://go.microsoft.com/fwlink/?LinkID=746393.
  Stack Trace: 
    NavigationExpandingExpressionVisitor.<ProcessInclude>g__ExtractIncludeFilter|31_0(Expression currentExpression, Expression includeExpression)
    NavigationExpandingExpressionVisitor.<ProcessInclude>g__ExtractIncludeFilter|31_0(Expression currentExpression, Expression includeExpression)
    NavigationExpandingExpressionVisitor.<ProcessInclude>g__ExtractIncludeFilter|31_0(Expression currentExpression, Expression includeExpression)
    NavigationExpandingExpressionVisitor.ProcessInclude(NavigationExpansionExpression source, Expression expression, Boolean thenInclude)
    NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
    MethodCallExpression.Accept(ExpressionVisitor visitor)
    ExpressionVisitor.Visit(Expression node)
    NavigationExpandingExpressionVisitor.Expand(Expression query)
    QueryTranslationPreprocessor.Process(Expression query)
    RelationalQueryTranslationPreprocessor.Process(Expression query)
    QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
    Database.CompileQuery[TResult](Expression query, Boolean async)
    QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
    <>c__DisplayClass9_0`1.<Execute>b__0()
    CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
    QueryCompiler.Execute[TResult](Expression query)
    EntityQueryProvider.Execute[TResult](Expression expression)
    EntityQueryable`1.GetEnumerator()
    IncludableQueryable`2.GetEnumerator()
    List`1.ctor(IEnumerable`1 collection)
    Enumerable.ToList[TSource](IEnumerable`1 source)
    Ch02_IncludeSortFilter.TestThenIncludeSortSingle() line 207

And here's the original code of this test:

    [Fact]
    public void TestThenIncludeSortSingle()
    {
        //SETUP
        var options = SqliteInMemory.CreateOptions<EfCoreContext>();
        using var context = new EfCoreContext(options);
        context.Database.EnsureCreated();
        var newBook = new Book
        {
            AuthorsLink = new List<BookAuthor>
            {
                new BookAuthor {Author = new Author {Name = "Author2"}, Order = 2},
                new BookAuthor {Author = new Author {Name = "Author1"}, Order = 1},
            }
        };
        context.Add(newBook);
        context.SaveChanges();

        //ATTEMPT
        var query = context.Books
            .Include(book => book.AuthorsLink)//.OrderBy(y => y.Order))
            .ThenInclude(bookAuthor => bookAuthor.OrderBy(y => y.Author.Name));
        var books = query.ToList();

        //VERIFY
        _output.WriteLine(query.ToQueryString());
        books.Single().AuthorsLink.Select(x => x.Author.Name).ShouldEqual(new[] { "Author1", "Author2" });
    }

It would seem like it is impossible for EF to do an OrderBy() inside the ThenInclude(x => [...]) lambda. How can we make this test repass correctly?

Hi @Juansero29,

Yes, I know this unit test fails. I thought would work but it doesn't and I haven't found a way to do get it to work. Therefore I left it as a failing unit test because it points out that there are limitations on this new feature

Hello @JonPSmith,
I just ran into this myself. I believe that since this test is now existing to showcase a limitation, that the test should be adjusted to verify this limitation instead of having broken unit tests on a fresh clone. I was left wondering for a bit if my local system had some difference that was making it fail, and Google wasn't helping. Then I found this Issue and all was made clear.

But to document this intention in the code, the test could be changed to something like the following:

[Fact]
public void TestThenIncludeSortSingle()
{
    //SETUP
    // ...No changes to Setup...

    //ATTEMPT
    var query = context.Books
        .Include(book => book.AuthorsLink) //.OrderBy(y => y.Order))
        .ThenInclude(bookAuthor => bookAuthor.OrderBy(y => y.Author.Name));
    void ExecuteQueryAction() => query.ToList();

    //VERIFY
    // Could not get this to work due to limitations on this new feature. See https://github.com/JonPSmith/EfCoreinAction-SecondEdition/issues/7
    // The expression 'bookAuthor.AsQueryable().OrderBy(y => y.Author.Name)' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'.
    Assert.Throws<InvalidOperationException>(ExecuteQueryAction);
}

Alternatively, the test could be skipped with an explanation:

[Fact(Skip = "Could not get this to work due to limitations on this new feature. See https://github.com/JonPSmith/EfCoreinAction-SecondEdition/issues/7")]

image

I believe this would be a better experience for those expecting a fresh clone / checkout of master to work out of the box.

Thanks!

P.S.
Just by cracking open this solution I learned about ToQueryString() and ITestOutputHelper, two very useful things. Also, the book's been a good read so far (just got into part 2).