Skip to content

Commit

Permalink
Test for entity type with navigation mapped to SqlQuery (#28990)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers authored Sep 7, 2022
1 parent 17ea4d0 commit d67de27
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 0 deletions.
130 changes: 130 additions & 0 deletions test/EFCore.Relational.Specification.Tests/Query/ToSqlQueryTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable enable

namespace Microsoft.EntityFrameworkCore.Query;

public abstract class ToSqlQueryTestBase : NonSharedModelTestBase
{
protected override string StoreName
=> "ToSqlQueryTests";

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))] // Issue #27629
public virtual async Task Entity_type_with_navigation_mapped_to_SqlQuery(bool async)
{
var contextFactory = await InitializeAsync<Context27629>(seed: c =>
{
var author = new Author { Name = "Toast", Posts = { new() { Title = "Sausages of the world!"} } };
c.Add(author);
c.SaveChanges();
var postStat = new PostStat { Count = 10, Author = author };
author.PostStat = postStat;
c.Add(postStat);
c.SaveChanges();
});

using var context = contextFactory.CreateContext();

var authors = await
(from o in context.Authors
select new
{
Author = o,
PostCount = o.PostStat!.Count
}).ToListAsync();

Assert.Single(authors);
Assert.Equal("Toast", authors[0].Author.Name);
Assert.Equal(10, authors[0].PostCount);
}

protected class Context27629 : DbContext
{
public Context27629(DbContextOptions options)
: base(options)
{
}

public DbSet<Author> Authors
=> Set<Author>();

public DbSet<Post> Posts
=> Set<Post>();

public DbSet<PostStat> PostStats
=> Set<PostStat>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>(
builder =>
{
builder.ToTable("Authors");
builder.Property(o => o.Name).HasMaxLength(50);
});

modelBuilder.Entity<Post>(
builder =>
{
builder.ToTable("Posts");
builder.Property(o => o.Title).HasMaxLength(50);
builder.Property(o => o.Content).HasMaxLength(500);
builder
.HasOne(o => o.Author)
.WithMany(o => o.Posts)
.HasForeignKey(o => o.AuthorId)
.OnDelete(DeleteBehavior.ClientCascade);
});

modelBuilder.Entity<PostStat>(
builder =>
{
builder
.ToSqlQuery("SELECT * FROM PostStats")
.HasKey(o => o.AuthorId);
builder
.HasOne(o => o.Author)
.WithOne().HasForeignKey<PostStat>(o => o.AuthorId)
.OnDelete(DeleteBehavior.ClientCascade);
});
}
}

protected class Author
{
public long Id { get; set; }
public string Name { get; set; } = null!;
public List<Post> Posts { get; } = new();
public PostStat? PostStat { get; set; }
}

protected class Post
{
public long Id { get; set; }
public long AuthorId { get; set; }
public Author Author { get; set; } = null!;
public string? Title { get; set; }
public string? Content { get; set; }
}

protected class PostStat
{
public long AuthorId { get; set; }
public Author Author { get; set; } = null!;
public long? Count { get; set; }
}

public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());

protected TestSqlLoggerFactory TestSqlLoggerFactory
=> (TestSqlLoggerFactory)ListLoggerFactory;

protected void ClearLog()
=> TestSqlLoggerFactory.Clear();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Query;

public class ToSqlQuerySqlServerTest : ToSqlQueryTestBase
{
protected override ITestStoreFactory TestStoreFactory
=> SqlServerTestStoreFactory.Instance;

[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());

public override async Task Entity_type_with_navigation_mapped_to_SqlQuery(bool async)
{
await base.Entity_type_with_navigation_mapped_to_SqlQuery(async);

AssertSql(
@"SELECT [a].[Id], [a].[Name], [a].[PostStatAuthorId], [m].[Count] AS [PostCount]
FROM [Authors] AS [a]
LEFT JOIN (
SELECT * FROM PostStats
) AS [m] ON [a].[PostStatAuthorId] = [m].[AuthorId]");
}

private void AssertSql(params string[] expected)
=> TestSqlLoggerFactory.AssertBaseline(expected);
}
29 changes: 29 additions & 0 deletions test/EFCore.Sqlite.FunctionalTests/Query/ToSqlQuerySqliteTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Query;

public class ToSqlQuerySqliteTest : ToSqlQueryTestBase
{
protected override ITestStoreFactory TestStoreFactory
=> SqliteTestStoreFactory.Instance;

[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());

public override async Task Entity_type_with_navigation_mapped_to_SqlQuery(bool async)
{
await base.Entity_type_with_navigation_mapped_to_SqlQuery(async);

AssertSql(
@"SELECT ""a"".""Id"", ""a"".""Name"", ""a"".""PostStatAuthorId"", ""m"".""Count"" AS ""PostCount""
FROM ""Authors"" AS ""a""
LEFT JOIN (
SELECT * FROM PostStats
) AS ""m"" ON ""a"".""PostStatAuthorId"" = ""m"".""AuthorId""");
}

private void AssertSql(params string[] expected)
=> TestSqlLoggerFactory.AssertBaseline(expected);
}

0 comments on commit d67de27

Please sign in to comment.