From a1bc1f47ccc8235866fe9daabd5fe892094c846f Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Thu, 10 Nov 2022 07:42:53 -0800 Subject: [PATCH] Fix to #29365 - Query/Test: convert FromSql tests to use query infra (#29402) Fixes #29365 --- .../Query/FromSqlQueryTestBase.cs | 1425 +++++++---------- .../Query/FromSqlQuerySqlServerTest.cs | 16 +- .../Query/FromSqlQuerySqliteTest.cs | 12 +- 3 files changed, 610 insertions(+), 843 deletions(-) diff --git a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs index e9d6dc19303..bade662fa1b 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs @@ -1,7 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Data; +using System.Runtime.Intrinsics.X86; +using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; using Microsoft.EntityFrameworkCore.TestModels.Northwind; // ReSharper disable FormatStringProblem @@ -10,22 +13,19 @@ // ReSharper disable AccessToDisposedClosure namespace Microsoft.EntityFrameworkCore.Query; -public abstract class FromSqlQueryTestBase : IClassFixture + +public abstract class FromSqlQueryTestBase : QueryTestBase where TFixture : NorthwindQueryRelationalFixture, new() { // ReSharper disable once StaticMemberInGenericType private static readonly string _eol = Environment.NewLine; protected FromSqlQueryTestBase(TFixture fixture) + : base(fixture) { - Fixture = fixture; Fixture.TestSqlLoggerFactory.Clear(); } - protected TFixture Fixture { get; } - - public static IEnumerable IsAsyncData = new[] { new object[] { false }, new object[] { true } }; - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Bad_data_error_handling_invalid_cast_key(bool async) @@ -152,53 +152,35 @@ public virtual async Task Bad_data_error_handling_null_no_tracking(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple(bool async) - { - using var context = CreateContext(); - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(14, actual.Length); - Assert.Equal(14, context.ChangeTracker.Entries().Count()); - } + public virtual Task FromSqlRaw_queryable_simple(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")), + ss => ss.Set().Where(x => x.ContactName.Contains("z")), + entryCount: 14); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT [Region], [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(91, actual.Length); - Assert.Equal(91, context.ChangeTracker.Entries().Count()); - } + public virtual Task FromSqlRaw_queryable_simple_columns_out_of_order(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString( + "SELECT [Region], [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")), + ss => ss.Set(), + entryCount: 91); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order_and_extra_columns(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT [Region], [PostalCode], [PostalCode] AS [Foo], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(91, actual.Length); - Assert.Equal(91, context.ChangeTracker.Entries().Count()); - } + public virtual Task FromSqlRaw_queryable_simple_columns_out_of_order_and_extra_columns(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString( + "SELECT [Region], [PostalCode], [PostalCode] AS [Foo], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")), + ss => ss.Set(), + entryCount: 91); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -218,39 +200,26 @@ public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order_and_n [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_composed(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Where(c => c.ContactName.Contains("z")); - - var queryString = query.ToQueryString(); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(14, actual.Length); - - return queryString; - } + public virtual Task FromSqlRaw_queryable_composed(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Where(c => c.ContactName.Contains("z")), + ss => ss.Set().Where(c => c.ContactName.Contains("z")), + entryCount: 14); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_composed_after_removing_whitespaces(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( + public virtual Task FromSqlRaw_queryable_composed_after_removing_whitespaces(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString( _eol + " " + _eol + _eol + _eol + "SELECT" + _eol + "* FROM [Customers]")) - .Where(c => c.ContactName.Contains("z")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(14, actual.Length); - } + .Where(c => c.ContactName.Contains("z")), + ss => ss.Set().Where(c => c.ContactName.Contains("z")), + entryCount: 14); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -400,80 +369,74 @@ public virtual async Task FromSqlRaw_queryable_composed_compiled_with_nameless_D [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_composed_contains(bool async) - { - using var context = CreateContext(); - var query = from c in context.Set() - where context.Orders.FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) - .Select(o => o.CustomerID) - .Contains(c.CustomerID) - select c; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(89, actual.Length); - } + public virtual Task FromSqlRaw_composed_contains(bool async) + => AssertQuery( + async, + ss => from c in ss.Set() + where ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) + .Select(o => o.CustomerID) + .Contains(c.CustomerID) + select c, + ss => from c in ss.Set() + where ss.Set() + .Select(o => o.CustomerID) + .Contains(c.CustomerID) + select c, + entryCount: 89); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_composed_contains2(bool async) - { - using var context = CreateContext(); - var query = from c in context.Set() - where - c.CustomerID == "ALFKI" - && context.Orders.FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) - .Select(o => o.CustomerID) - .Contains(c.CustomerID) - select c; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); - } + public virtual Task FromSqlRaw_composed_contains2(bool async) + => AssertQuery( + async, + ss => from c in ss.Set() + where + c.CustomerID == "ALFKI" + && ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) + .Select(o => o.CustomerID) + .Contains(c.CustomerID) + select c, + ss => from c in ss.Set() + where c.CustomerID == "ALFKI" && ss.Set().Select(o => o.CustomerID).Contains(c.CustomerID) + select c, + entryCount: 1); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_multiple_composed(bool async) - { - using var context = CreateContext(); - var query = from c in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - from o in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) - where c.CustomerID == o.CustomerID - select new { c, o }; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(830, actual.Length); - } + public virtual Task FromSqlRaw_queryable_multiple_composed(bool async) + => AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + from o in ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set() + from o in ss.Set() + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 919); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_multiple_composed_with_closure_parameters(bool async) + public virtual Task FromSqlRaw_queryable_multiple_composed_with_closure_parameters(bool async) { var startDate = new DateTime(1997, 1, 1); var endDate = new DateTime(1998, 1, 1); - using var context = CreateContext(); - var query = from c in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - from o in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), - startDate, - endDate) - where c.CustomerID == o.CustomerID - select new { c, o }; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(411, actual.Length); + return AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + from o in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), + startDate, + endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set() + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 497); } [ConditionalTheory] @@ -484,196 +447,149 @@ public virtual async Task FromSqlRaw_queryable_multiple_composed_with_parameters var startDate = new DateTime(1997, 1, 1); var endDate = new DateTime(1998, 1, 1); - using var context = CreateContext(); - var query = from c in context.Set().FromSqlRaw( + await AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - from o in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), - startDate, - endDate) - where c.CustomerID == o.CustomerID - select new { c, o }; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(25, actual.Length); + from o in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), + startDate, + endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.City == city) + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 31); city = "Berlin"; startDate = new DateTime(1998, 4, 1); endDate = new DateTime(1998, 5, 1); - query = (from c in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - from o in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), - startDate, - endDate) - where c.CustomerID == o.CustomerID - select new { c, o }); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); + await AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + from o in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), + startDate, + endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.City == city) + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 2); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_multiple_line_query(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( + public virtual Task FromSqlRaw_queryable_multiple_line_query(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString( @"SELECT * FROM [Customers] -WHERE [City] = 'London'")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - } +WHERE [City] = 'London'")), + ss => ss.Set().Where(x => x.City == "London"), + entryCount: 6); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_composed_multiple_line_query(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( + public virtual Task FromSqlRaw_queryable_composed_multiple_line_query(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString( @"SELECT * FROM [Customers]")) - .Where(c => c.City == "London"); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - } + .Where(c => c.City == "London"), + ss => ss.Set().Where(x => x.City == "London"), + entryCount: 6); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_with_parameters(bool async) + public virtual Task FromSqlRaw_queryable_with_parameters(bool async) { var city = "London"; var contactTitle = "Sales Representative"; - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, - contactTitle); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); + return AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, + contactTitle), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == contactTitle), + entryCount: 3); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_with_parameters_inline(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), "London", - "Sales Representative"); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); - } + public virtual Task FromSqlRaw_queryable_with_parameters_inline(bool async) + => AssertQuery( + async, + ss => ((DbSet) ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), "London", + "Sales Representative"), + ss => ss.Set().Where(x => x.City == "London" && x.ContactTitle == "Sales Representative"), + entryCount: 3); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlInterpolated_queryable_with_parameters_interpolated(bool async) + public virtual Task FromSqlInterpolated_queryable_with_parameters_interpolated(bool async) { var city = "London"; var contactTitle = "Sales Representative"; - using var context = CreateContext(); - var query = context.Set().FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Customers] WHERE [City] = {city} AND [ContactTitle] = {contactTitle}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); + return AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlInterpolated( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Customers] WHERE [City] = {city} AND [ContactTitle] = {contactTitle}")), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == contactTitle), + entryCount: 3); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSql_queryable_with_parameters_interpolated(bool async) + public virtual Task FromSql_queryable_with_parameters_interpolated(bool async) { var city = "London"; var contactTitle = "Sales Representative"; - using var context = CreateContext(); - var query = context.Set().FromSql( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Customers] WHERE [City] = {city} AND [ContactTitle] = {contactTitle}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); + return AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSql( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Customers] WHERE [City] = {city} AND [ContactTitle] = {contactTitle}")), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == contactTitle), + entryCount: 3); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlInterpolated_queryable_with_parameters_inline_interpolated(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Customers] WHERE [City] = {"London"} AND [ContactTitle] = {"Sales Representative"}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); - } + public virtual Task FromSqlInterpolated_queryable_with_parameters_inline_interpolated(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlInterpolated( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Customers] WHERE [City] = {"London"} AND [ContactTitle] = {"Sales Representative"}")), + ss => ss.Set().Where(x => x.City == "London" && x.ContactTitle == "Sales Representative"), + entryCount: 3); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSql_queryable_with_parameters_inline_interpolated(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSql( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Customers] WHERE [City] = {"London"} AND [ContactTitle] = {"Sales Representative"}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); - } + public virtual Task FromSql_queryable_with_parameters_inline_interpolated(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSql( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Customers] WHERE [City] = {"London"} AND [ContactTitle] = {"Sales Representative"}")), + ss => ss.Set().Where(x => x.City == "London" && x.ContactTitle == "Sales Representative"), + entryCount: 3); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -684,40 +600,39 @@ public virtual async Task FromSqlInterpolated_queryable_multiple_composed_with_p var startDate = new DateTime(1997, 1, 1); var endDate = new DateTime(1998, 1, 1); - using var context = CreateContext(); - var query - = from c in context.Set().FromSqlRaw( + await AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - from o in context.Set().FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) - where c.CustomerID == o.CustomerID - select new { c, o }; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(25, actual.Length); + from o in ((DbSet)ss.Set()).FromSqlInterpolated( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.City == city) + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 31); city = "Berlin"; startDate = new DateTime(1998, 4, 1); endDate = new DateTime(1998, 5, 1); - query - = (from c in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - from o in context.Set().FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) - where c.CustomerID == o.CustomerID - select new { c, o }); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); + await AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + from o in ((DbSet)ss.Set()).FromSqlInterpolated( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.City == city) + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 2); } [ConditionalTheory] @@ -729,59 +644,55 @@ public virtual async Task FromSql_queryable_multiple_composed_with_parameters_an var startDate = new DateTime(1997, 1, 1); var endDate = new DateTime(1998, 1, 1); - using var context = CreateContext(); - var query - = from c in context.Set().FromSqlRaw( + await AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - from o in context.Set().FromSql( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) - where c.CustomerID == o.CustomerID - select new { c, o }; - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(25, actual.Length); + from o in ((DbSet)ss.Set()).FromSql( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.City == city) + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 31); city = "Berlin"; startDate = new DateTime(1998, 4, 1); endDate = new DateTime(1998, 5, 1); - query - = (from c in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - from o in context.Set().FromSql( - NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) - where c.CustomerID == o.CustomerID - select new { c, o }); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); + await AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + from o in ((DbSet)ss.Set()).FromSql( + NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) + where c.CustomerID == o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.City == city) + from o in ss.Set().Where(x => x.OrderDate >= startDate && x.OrderDate <= endDate) + where c.CustomerID == o.CustomerID + select new { c, o }, + entryCount: 2); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_with_null_parameter(bool async) + public virtual Task FromSqlRaw_queryable_with_null_parameter(bool async) { uint? reportsTo = null; - using var context = CreateContext(); - var query = context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - // ReSharper disable once ExpressionIsAlwaysNull - "SELECT * FROM [Employees] WHERE [ReportsTo] = {0} OR ([ReportsTo] IS NULL AND {0} IS NULL)"), reportsTo); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); + return AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString( + // ReSharper disable once ExpressionIsAlwaysNull + "SELECT * FROM [Employees] WHERE [ReportsTo] = {0} OR ([ReportsTo] IS NULL AND {0} IS NULL)"), reportsTo), + ss => ss.Set().Where(x => x.ReportsTo == reportsTo), + entryCount: 1); } [ConditionalTheory] @@ -812,26 +723,19 @@ public virtual async Task FromSqlRaw_queryable_with_parameters_and_closu [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlRaw_queryable_simple_cache_key_includes_query_string(bool async) { - using var context = CreateContext(); - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - - query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")), + ss => ss.Set().Where(x => x.City == "London"), + entryCount: 6); - Assert.Single(actual); - Assert.True(actual.All(c => c.City == "Seattle")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")), + ss => ss.Set().Where(x => x.City == "Seattle"), + entryCount: 1); } [ConditionalTheory] @@ -842,100 +746,81 @@ public virtual async Task FromSqlRaw_queryable_with_parameters_cache_key_include var contactTitle = "Sales Representative"; var sql = "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"; - using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == contactTitle), + entryCount: 3); city = "Madrid"; contactTitle = "Accounting Manager"; - query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(2, actual.Length); - Assert.True(actual.All(c => c.City == "Madrid")); - Assert.True(actual.All(c => c.ContactTitle == "Accounting Manager")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == contactTitle), + entryCount: 2); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_as_no_tracking_not_composed(bool async) + public virtual Task FromSqlRaw_queryable_simple_as_no_tracking_not_composed(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .AsNoTracking(), + ss => ss.Set()); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_projection_composed(bool async) { using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .AsNoTracking(); + var boolMapping = (RelationalTypeMapping)context.GetService().FindMapping(typeof(bool)); + var boolLiteral = boolMapping.GenerateSqlLiteral(true); - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(91, actual.Length); - Assert.Empty(context.ChangeTracker.Entries()); - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_projection_composed(bool async) - { - using var context = CreateContext(); - var boolMapping = (RelationalTypeMapping)context.GetService().FindMapping(typeof(bool)); - var query = context.Set().FromSqlRaw( + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString( @"SELECT * FROM [Products] WHERE [Discontinued] <> " - + boolMapping.GenerateSqlLiteral(true) + + boolLiteral + @" AND (([UnitsInStock] + [UnitsOnOrder]) < [ReorderLevel])")) - .Select(p => p.ProductName); + .Select(p => p.ProductName), - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(2, actual.Length); + ss => ss.Set() + .Where(x => x.Discontinued != true && (x.UnitsInStock + x.UnitsOnOrder) < x.ReorderLevel) + .Select(x => x.ProductName)); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_include(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Include(c => c.Orders); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(830, actual.SelectMany(c => c.Orders).Count()); - } + public virtual Task FromSqlRaw_queryable_simple_include(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Include(c => c.Orders), + ss => ss.Set(), + elementAsserter: (e, a) => AssertInclude(e, a, new ExpectedInclude(x => x.Orders)), + entryCount: 921); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_composed_include(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Include(c => c.Orders) - .Where(c => c.City == "London"); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(46, actual.SelectMany(c => c.Orders).Count()); - } + public virtual Task FromSqlRaw_queryable_simple_composed_include(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Include(c => c.Orders) + .Where(c => c.City == "London"), + ss => ss.Set().Where(c => c.City == "London"), + elementAsserter: (e, a) => AssertInclude(e, a, new ExpectedInclude(x => x.Orders)), + entryCount: 52); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -961,90 +846,68 @@ public virtual async Task FromSqlRaw_annotations_do_not_affect_successive_calls( [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_composed_with_nullable_predicate(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Where(c => c.ContactName == c.CompanyName); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Empty(actual); - } + public virtual Task FromSqlRaw_composed_with_nullable_predicate(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Where(c => c.ContactName == c.CompanyName), + ss => ss.Set().Where(c => c.ContactName == c.CompanyName)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlRaw_with_dbParameter(bool async) { - using var context = CreateContext(); var parameter = CreateDbParameter("@city", "London"); - var query = context.Customers.FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter), + ss => ss.Set().Where(x => x.City == "London"), + entryCount: 6); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlRaw_with_dbParameter_without_name_prefix(bool async) { - using var context = CreateContext(); var parameter = CreateDbParameter("city", "London"); - var query = context.Customers.FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter), + ss => ss.Set().Where(x => x.City == "London"), + entryCount: 6); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlRaw_with_dbParameter_mixed(bool async) { - using var context = CreateContext(); var city = "London"; var title = "Sales Representative"; var titleParameter = CreateDbParameter("@title", title); - var query = context.Customers.FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = @title"), city, titleParameter); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString( + "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = @title"), city, titleParameter), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == title), + entryCount: 3); var cityParameter = CreateDbParameter("@city", city); - query = context.Customers.FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT * FROM [Customers] WHERE [City] = @city AND [ContactTitle] = {1}"), cityParameter, title); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString( + "SELECT * FROM [Customers] WHERE [City] = @city AND [ContactTitle] = {1}"), cityParameter, title), + ss => ss.Set().Where(x => x.City == city && x.ContactTitle == title), + entryCount: 3); } [ConditionalTheory] @@ -1108,59 +971,48 @@ public virtual async Task FromSqlRaw_with_db_parameters_called_multiple_times(bo [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_with_SelectMany_and_include(bool async) - { - using var context = CreateContext(); - var query = from c1 in context.Set() + public virtual Task FromSqlRaw_with_SelectMany_and_include(bool async) + => AssertQuery( + async, + ss => from c1 in ((DbSet)ss.Set()) .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'ALFKI'")) - from c2 in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'AROUT'")) - .Include(c => c.Orders) - select new { c1, c2 }; - - var result = async - ? await query.ToArrayAsync() - : query.ToArray(); - Assert.Single(result); - - var customers1 = result.Select(r => r.c1); - var customers2 = result.Select(r => r.c2); - foreach (var customer1 in customers1) - { - Assert.Null(customer1.Orders); - } - - foreach (var customer2 in customers2) - { - Assert.NotNull(customer2.Orders); - } - } + from c2 in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'AROUT'")) + .Include(c => c.Orders) + select new { c1, c2 }, + ss => from c1 in ss.Set().Where(x => x.CustomerID == "ALFKI") + from c2 in ss.Set().Where(x => x.CustomerID == "AROUT") + select new { c1, c2 }, + elementAsserter: (e, a) => + { + AssertEqual(e.c1, a.c1); + AssertInclude(e.c2, a.c2, new ExpectedInclude(x => x.Orders)); + }, + entryCount: 15); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_with_join_and_include(bool async) - { - using var context = CreateContext(); - var query = from c in context.Set() + public virtual Task FromSqlRaw_with_join_and_include(bool async) + => AssertQuery( + async, + ss => from c in ((DbSet)ss.Set()) .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'ALFKI'")) - join o in context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderID] <> 1")) - .Include(o => o.OrderDetails) - on c.CustomerID equals o.CustomerID - select new { c, o }; - - var result = async - ? await query.ToListAsync() - : query.ToList(); - - Assert.Equal(6, result.Count); - - var orders = result.Select(r => r.o); - foreach (var order in orders) - { - Assert.NotNull(order.OrderDetails); - } - } + join o in ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderID] <> 1")) + .Include(o => o.OrderDetails) + on c.CustomerID equals o.CustomerID + select new { c, o }, + ss => from c in ss.Set().Where(x => x.CustomerID == "ALFKI") + join o in ss.Set().Where(x => x.OrderID != 1) + on c.CustomerID equals o.CustomerID + select new { c, o }, + elementSorter: e => (e.c.CustomerID, e.o.OrderID), + elementAsserter: (e, a) => + { + AssertEqual(e.c, a.c); + AssertInclude(e.o, a.o, new ExpectedInclude(x => x.OrderDetails)); + }, + entryCount: 19); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1188,76 +1040,60 @@ public virtual async Task Include_closed_connection_opened_by_it_when_buffering( [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlInterpolated_with_inlined_db_parameter(bool async) { - using var context = CreateContext(); var parameter = CreateDbParameter("@somename", "ALFKI"); - var query = context.Customers - .FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); - Assert.True(actual.All(c => c.City == "Berlin")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlInterpolated( + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI"), + entryCount: 1); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSql_with_inlined_db_parameter(bool async) { - using var context = CreateContext(); var parameter = CreateDbParameter("@somename", "ALFKI"); - var query = context.Customers - .FromSql( - NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); - Assert.True(actual.All(c => c.City == "Berlin")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSql( + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI"), + entryCount: 1); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlInterpolated_with_inlined_db_parameter_without_name_prefix(bool async) { - using var context = CreateContext(); var parameter = CreateDbParameter("somename", "ALFKI"); - var query = context.Customers - .FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); - Assert.True(actual.All(c => c.City == "Berlin")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlInterpolated( + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI"), + entryCount: 1); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSql_with_inlined_db_parameter_without_name_prefix(bool async) { - using var context = CreateContext(); var parameter = CreateDbParameter("somename", "ALFKI"); - var query = context.Customers - .FromSql( - NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Single(actual); - Assert.True(actual.All(c => c.City == "Berlin")); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSql( + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI"), + entryCount: 1); } [ConditionalTheory] @@ -1303,340 +1139,287 @@ public virtual async Task FromSqlInterpolated_parameterization_issue_12213(bool [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlRaw_does_not_parameterize_interpolated_string(bool async) { - using var context = CreateContext(); var tableName = "Orders"; var max = 10250; - var query = context.Orders.FromSqlRaw( - NormalizeDelimitersInRawString($"SELECT * FROM [{tableName}] WHERE [OrderID] < {{0}}"), max); - - var actual = async - ? await query.ToListAsync() - : query.ToList(); - Assert.Equal(2, actual.Count); + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + NormalizeDelimitersInRawString($"SELECT * FROM [{tableName}] WHERE [OrderID] < {{0}}"), max), + ss => ss.Set().Where(x => x.OrderID < max), + entryCount: 2); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task Entity_equality_through_fromsql(bool async) - { - using var context = CreateContext(); - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) - .Where(o => o.Customer == new Customer { CustomerID = "VINET" }); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(5, actual.Length); - } + public virtual Task Entity_equality_through_fromsql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) + .Where(o => o.Customer == new Customer { CustomerID = "VINET" }), + ss => ss.Set().Where(o => o.Customer == new Customer { CustomerID = "VINET" }), + entryCount: 5); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_with_set_operation(bool async) - { - using var context = CreateContext(); - - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) - .Concat( - context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Berlin'"))); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(7, actual.Length); - } + public virtual Task FromSqlRaw_with_set_operation(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) + .Concat(((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Berlin'"))), + ss => ss.Set().Where(x => x.City == "London") + .Concat(ss.Set().Where(x => x.City == "Berlin")), + entryCount: 7); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task Keyless_entity_with_all_nulls(bool async) - { - using var context = CreateContext(); - - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT NULL AS [CustomerID] FROM [Customers] WHERE [City] = 'Berlin'")) - .IgnoreQueryFilters(); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.NotNull(Assert.Single(actual)); - } + public virtual Task Keyless_entity_with_all_nulls(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT NULL AS [CustomerID] FROM [Customers] WHERE [City] = 'Berlin'")) + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.City == "Berlin").Select(x => new OrderQuery(null))); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSql_used_twice_without_parameters(bool async) { - using var context = CreateContext(); + await AssertAny( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT 'ALFKI' AS [CustomerID]")) + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT 'ALFKI' AS [CustomerID]")) - .IgnoreQueryFilters(); - - var result1 = async - ? await query.AnyAsync() - : query.Any(); - - var result2 = async - ? await query.AnyAsync() - : query.Any(); - - Assert.Equal(result1, result2); + await AssertAny( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT 'ALFKI' AS [CustomerID]")) + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSql_used_twice_with_parameters(bool async) { - using var context = CreateContext(); - - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT {0} AS [CustomerID]"), "ALFKI") - .IgnoreQueryFilters(); - - var result1 = async - ? await query.AnyAsync() - : query.Any(); - - var result2 = async - ? await query.AnyAsync() - : query.Any(); + await AssertAny( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT {0} AS [CustomerID]"), "ALFKI") + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); - Assert.Equal(result1, result2); + await AssertAny( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT {0} AS [CustomerID]"), "ALFKI") + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSql_Count_used_twice_without_parameters(bool async) { - using var context = CreateContext(); + await AssertCount( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT 'ALFKI' AS [CustomerID]")) + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT 'ALFKI' AS [CustomerID]")) - .IgnoreQueryFilters(); - - var result1 = async - ? await query.CountAsync() > 0 - : query.Count() > 0; - - var result2 = async - ? await query.CountAsync() > 0 - : query.Count() > 0; + await AssertCount( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT 'ALFKI' AS [CustomerID]")) + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSql_Count_used_twice_with_parameters(bool async) { - using var context = CreateContext(); - - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT {0} AS [CustomerID]"), "ALFKI") - .IgnoreQueryFilters(); - - var result1 = async - ? await query.CountAsync() > 0 - : query.Count() > 0; - - var result2 = async - ? await query.CountAsync() > 0 - : query.Count() > 0; - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task Line_endings_after_Select(bool async) - { - using var context = CreateContext(); - - var query = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT" + Environment.NewLine + "* FROM [Customers]")) - .Where(e => e.City == "Seattle"); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.NotNull(actual); - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSql_with_db_parameter_in_split_query(bool async) - { - using var context = CreateContext(); - - var query = context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), - CreateDbParameter("customerID", "ALFKI")) - .Include(e => e.Orders) - .ThenInclude(o => o.OrderDetails) - .AsSplitQuery(); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - var customer = Assert.Single(actual); - Assert.Equal(6, customer.Orders.Count); - Assert.Equal(12, customer.Orders.SelectMany(e => e.OrderDetails).Count()); - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_queryable_simple_projection_not_composed(bool async) - { - using var context = CreateContext(); - var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Select( - c => new { c.CustomerID, c.City }) - .AsNoTracking(); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(91, actual.Length); - Assert.Empty(context.ChangeTracker.Entries()); - } + await AssertCount( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT {0} AS [CustomerID]"), "ALFKI") + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); + + await AssertCount( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT {0} AS [CustomerID]"), "ALFKI") + .IgnoreQueryFilters(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI").Select(x => new OrderQuery(x.CustomerID))); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Line_endings_after_Select(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT" + Environment.NewLine + "* FROM [Customers]")) + .Where(e => e.City == "Seattle"), + ss => ss.Set().Where(x => x.City == "Seattle"), + entryCount: 1); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task FromSql_with_db_parameter_in_split_query(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), + CreateDbParameter("customerID", "ALFKI")) + .Include(e => e.Orders) + .ThenInclude(o => o.OrderDetails) + .AsSplitQuery(), + ss => ss.Set().Where(x => x.CustomerID == "ALFKI"), + elementAsserter: (e, a) => AssertInclude( + e, + a, + new ExpectedInclude(x => x.Orders), + new ExpectedInclude(x => x.OrderDetails, "Orders")), + entryCount: 19); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task FromSqlRaw_queryable_simple_projection_not_composed(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Select(c => new { c.CustomerID, c.City }) + .AsNoTracking(), + ss => ss.Set().Select(c => new { c.CustomerID, c.City }), + elementSorter: e => e.CustomerID, + elementAsserter: (e, a) => + { + Assert.Equal(e.CustomerID, a.CustomerID); + Assert.Equal(e.City, a.City); + }); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_in_subquery_with_dbParameter(bool async) - { - using var context = CreateContext(); - var query = context.Orders.Where( - o => - context.Customers - .FromSqlRaw( + public virtual Task FromSqlRaw_in_subquery_with_dbParameter(bool async) + => AssertQuery( + async, + ss => ss.Set().Where(o => ((DbSet)ss.Set()).FromSqlRaw( NormalizeDelimitersInRawString(@"SELECT * FROM [Customers] WHERE [City] = @city"), // ReSharper disable once FormatStringProblem CreateDbParameter("@city", "London")) - .Select(c => c.CustomerID) - .Contains(o.CustomerID)); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(46, actual.Length); - } + .Select(c => c.CustomerID) + .Contains(o.CustomerID)), + ss => ss.Set().Where(o => ss.Set().Where(x => x.City == "London") + .Select(c => c.CustomerID) + .Contains(o.CustomerID)), + entryCount: 46); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_in_subquery_with_positional_dbParameter_without_name(bool async) - { - using var context = CreateContext(); - var query = context.Orders.Where( - o => - context.Customers + public virtual Task FromSqlRaw_in_subquery_with_positional_dbParameter_without_name(bool async) + => AssertQuery( + async, + ss => ss.Set().Where( + o => ((DbSet)ss.Set()) .FromSqlRaw( NormalizeDelimitersInRawString(@"SELECT * FROM [Customers] WHERE [City] = {0}"), // ReSharper disable once FormatStringProblem CreateDbParameter(null, "London")) .Select(c => c.CustomerID) - .Contains(o.CustomerID)); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(46, actual.Length); - } + .Contains(o.CustomerID)), + ss => ss.Set().Where( + o => ss.Set().Where(x => x.City == "London") + .Select(c => c.CustomerID) + .Contains(o.CustomerID)), + entryCount: 46); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_in_subquery_with_positional_dbParameter_with_name(bool async) - { - using var context = CreateContext(); - var query = context.Orders.Where( - o => - context.Customers + public virtual Task FromSqlRaw_in_subquery_with_positional_dbParameter_with_name(bool async) + => AssertQuery( + async, + ss => ss.Set().Where( + o => ((DbSet)ss.Set()) .FromSqlRaw( NormalizeDelimitersInRawString(@"SELECT * FROM [Customers] WHERE [City] = {0}"), // ReSharper disable once FormatStringProblem CreateDbParameter("@city", "London")) .Select(c => c.CustomerID) - .Contains(o.CustomerID)); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(46, actual.Length); - } + .Contains(o.CustomerID)), + ss => ss.Set().Where( + o => ss.Set().Where(x => x.City == "London") + .Select(c => c.CustomerID) + .Contains(o.CustomerID)), + entryCount: 46); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task FromSqlRaw_with_dbParameter_mixed_in_subquery(bool async) { - using var context = CreateContext(); const string city = "London"; const string title = "Sales Representative"; - var query = context.Orders.Where( - o => - context.Customers + await AssertQuery( + async, + ss => ss.Set().Where( + o => ((DbSet)ss.Set()) .FromSqlRaw( NormalizeDelimitersInRawString(@"SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = @title"), city, // ReSharper disable once FormatStringProblem CreateDbParameter("@title", title)) .Select(c => c.CustomerID) - .Contains(o.CustomerID)); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(26, actual.Length); + .Contains(o.CustomerID)), + ss => ss.Set().Where( + o => ss.Set().Where(x => x.City == city && x.ContactTitle == title) + .Select(c => c.CustomerID) + .Contains(o.CustomerID)), + entryCount: 26); - query = context.Orders.Where( - o => - context.Customers + await AssertQuery( + async, + ss => ss.Set().Where( + o => ((DbSet)ss.Set()) .FromSqlRaw( NormalizeDelimitersInRawString(@"SELECT * FROM [Customers] WHERE [City] = @city AND [ContactTitle] = {1}"), // ReSharper disable once FormatStringProblem CreateDbParameter("@city", city), title) .Select(c => c.CustomerID) - .Contains(o.CustomerID)); - - actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(26, actual.Length); + .Contains(o.CustomerID)), + ss => ss.Set().Where( + o => ss.Set().Where(x => x.City == city && x.ContactTitle == title) + .Select(c => c.CustomerID) + .Contains(o.CustomerID)), + entryCount: 26); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task FromSqlRaw_composed_with_common_table_expression(bool async) - { - using var context = CreateContext(); - var query = context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString( + public virtual Task FromSqlRaw_composed_with_common_table_expression(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()) + .FromSqlRaw( + NormalizeDelimitersInRawString( @"WITH [Customers2] AS ( SELECT * FROM [Customers] ) SELECT * FROM [Customers2]")) - .Where(c => c.ContactName.Contains("z")); - - var actual = async - ? await query.ToArrayAsync() - : query.ToArray(); - - Assert.Equal(14, actual.Length); - Assert.Equal(14, context.ChangeTracker.Entries().Count()); - } - + .Where(c => c.ContactName.Contains("z")), + ss => ss.Set().Where(c => c.ContactName.Contains("z")), + entryCount: 14); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Multiple_occurrences_of_FromSql_with_db_parameter_adds_parameter_only_once(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs index f9c2e99e14e..dd571b961aa 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs @@ -43,18 +43,9 @@ public override async Task FromSqlRaw_queryable_simple_columns_out_of_order_and_ """); } - public override async Task FromSqlRaw_queryable_composed(bool async) + public override async Task FromSqlRaw_queryable_composed(bool async) { - var queryString = await base.FromSqlRaw_queryable_composed(async); - - var expected = -""" -SELECT [m].[CustomerID], [m].[Address], [m].[City], [m].[CompanyName], [m].[ContactName], [m].[ContactTitle], [m].[Country], [m].[Fax], [m].[Phone], [m].[PostalCode], [m].[Region] -FROM ( - SELECT * FROM "Customers" -) AS [m] -WHERE [m].[ContactName] LIKE N'%z%' -"""; + await base.FromSqlRaw_queryable_composed(async); AssertSql( """ @@ -64,9 +55,6 @@ WHERE [m].[ContactName] LIKE N'%z%' ) AS [m] WHERE [m].[ContactName] LIKE N'%z%' """); - Assert.Equal(expected, queryString, ignoreLineEndingDifferences: true); - - return null; } public override async Task FromSqlRaw_queryable_composed_after_removing_whitespaces(bool async) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs index ae6bcb1ebd5..f0c8ef67d43 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs @@ -13,22 +13,18 @@ public FromSqlQuerySqliteTest(NorthwindQuerySqliteFixture f //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } - public override async Task FromSqlRaw_queryable_composed(bool async) + public override async Task FromSqlRaw_queryable_composed(bool async) { - var queryString = await base.FromSqlRaw_queryable_composed(async); + await base.FromSqlRaw_queryable_composed(async); - var expected = + AssertSql( """ SELECT "m"."CustomerID", "m"."Address", "m"."City", "m"."CompanyName", "m"."ContactName", "m"."ContactTitle", "m"."Country", "m"."Fax", "m"."Phone", "m"."PostalCode", "m"."Region" FROM ( SELECT * FROM "Customers" ) AS "m" WHERE 'z' = '' OR instr("m"."ContactName", 'z') > 0 -"""; - - Assert.Equal(expected, queryString, ignoreLineEndingDifferences: true); - - return queryString; +"""); } public override async Task FromSqlRaw_queryable_with_parameters_and_closure(bool async)