diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs index d029963733a..da96edc4e31 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs @@ -2270,10 +2270,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Order"")"); } - [ConditionalFact(Skip = "Issue #17246")] - public override void Select_bitwise_or() + [ConditionalTheory(Skip = "Issue #17246")] + public override async Task Select_bitwise_or(bool async) { - base.Select_bitwise_or(); + await base.Select_bitwise_or(async); AssertSql( @"SELECT c @@ -2281,10 +2281,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } - [ConditionalFact(Skip = "Issue #17246")] - public override void Select_bitwise_or_multiple() + [ConditionalTheory(Skip = "Issue #17246")] + public override async Task Select_bitwise_or_multiple(bool async) { - base.Select_bitwise_or_multiple(); + await base.Select_bitwise_or_multiple(async); AssertSql( @"SELECT c @@ -2292,10 +2292,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } - [ConditionalFact(Skip = "Issue #17246")] - public override void Select_bitwise_and() + [ConditionalTheory(Skip = "Issue #17246")] + public override async Task Select_bitwise_and(bool async) { - base.Select_bitwise_and(); + await base.Select_bitwise_and(async); AssertSql( @"SELECT c @@ -2303,10 +2303,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } - [ConditionalFact(Skip = "Issue #17246")] - public override void Select_bitwise_and_or() + [ConditionalTheory(Skip = "Issue #17246")] + public override async Task Select_bitwise_and_or(bool async) { - base.Select_bitwise_and_or(); + await base.Select_bitwise_and_or(async); AssertSql( @"SELECT c @@ -2378,10 +2378,10 @@ FROM root c WHERE ((c[""Discriminator""] = ""Order"") AND ((c[""OrderID""] | 10248) = 10248))"); } - [ConditionalFact(Skip = "Issue #17246")] - public override void Select_bitwise_or_with_logical_or() + [ConditionalTheory(Skip = "Issue #17246")] + public override async Task Select_bitwise_or_with_logical_or(bool async) { - base.Select_bitwise_or_with_logical_or(); + await base.Select_bitwise_or_with_logical_or(async); AssertSql( @"SELECT c @@ -2389,10 +2389,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } - [ConditionalFact(Skip = "Issue #17246")] - public override void Select_bitwise_and_with_logical_and() + [ConditionalTheory(Skip = "Issue #17246")] + public override async Task Select_bitwise_and_with_logical_and(bool async) { - base.Select_bitwise_and_with_logical_and(); + await base.Select_bitwise_and_with_logical_and(async); AssertSql( @"SELECT c @@ -2602,10 +2602,10 @@ FROM root c WHERE ((c[""Discriminator""] = ""Order"") AND (c[""OrderDate""] != null))"); } - [ConditionalFact(Skip = "Issue#17246")] - public override void DefaultIfEmpty_without_group_join() + [ConditionalTheory(Skip = "Issue#17246")] + public override async Task DefaultIfEmpty_without_group_join(bool async) { - base.DefaultIfEmpty_without_group_join(); + await base.DefaultIfEmpty_without_group_join(async); AssertSql( @"SELECT c @@ -3820,16 +3820,6 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } - public override void Throws_on_concurrent_query_first() - { - // #13160 - } - - public override void Throws_on_concurrent_query_list() - { - // #13160 - } - [ConditionalTheory(Skip = "Issue#17246")] public override Task Entity_equality_through_nested_anonymous_type_projection(bool async) { diff --git a/test/EFCore.InMemory.FunctionalTests/Query/NorthwindAsyncSimpleQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/NorthwindAsyncSimpleQueryInMemoryTest.cs deleted file mode 100644 index e9b41537717..00000000000 --- a/test/EFCore.InMemory.FunctionalTests/Query/NorthwindAsyncSimpleQueryInMemoryTest.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; - -namespace Microsoft.EntityFrameworkCore.Query -{ - public class NorthwindAsyncSimpleQueryInMemoryTest : NorthwindAsyncSimpleQueryTestBase< - NorthwindQueryInMemoryFixture> - { - public NorthwindAsyncSimpleQueryInMemoryTest(NorthwindQueryInMemoryFixture fixture) - : base(fixture) - { - } - - // mapping to view not supported on InMemory - public override Task Query_backed_by_database_view() - => Task.CompletedTask; - } -} diff --git a/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs deleted file mode 100644 index c1543f63752..00000000000 --- a/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.TestModels.Northwind; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; - -// ReSharper disable AccessToDisposedClosure -// ReSharper disable InconsistentNaming -namespace Microsoft.EntityFrameworkCore.Query -{ - public abstract class AsyncFromSqlQueryTestBase : IClassFixture - where TFixture : NorthwindQueryRelationalFixture, new() - { - protected AsyncFromSqlQueryTestBase(TFixture fixture) - { - Fixture = fixture; - Fixture.TestSqlLoggerFactory.Clear(); - } - - protected TFixture Fixture { get; } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple() - { - using var context = CreateContext(); - var actual = await context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) - .ToArrayAsync(); - - Assert.Equal(14, actual.Length); - Assert.Equal(14, context.ChangeTracker.Entries().Count()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT [Region], [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) - .ToArrayAsync(); - - Assert.Equal(91, actual.Length); - Assert.Equal(91, context.ChangeTracker.Entries().Count()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order_and_extra_columns() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT [Region], [PostalCode], [PostalCode] AS [Foo], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) - .ToArrayAsync(); - - Assert.Equal(91, actual.Length); - Assert.Equal(91, context.ChangeTracker.Entries().Count()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_composed() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Where(c => c.ContactName.Contains("z")) - .ToArrayAsync(); - - Assert.Equal(14, actual.Length); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_multiple_composed() - { - using var context = CreateContext(); - var actual - = await (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 }) - .ToArrayAsync(); - - Assert.Equal(830, actual.Length); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_multiple_composed_with_closure_parameters() - { - var startDate = new DateTime(1997, 1, 1); - var endDate = new DateTime(1998, 1, 1); - - using var context = CreateContext(); - var actual - = await (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 }) - .ToArrayAsync(); - - Assert.Equal(411, actual.Length); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters() - { - var city = "London"; - var startDate = new DateTime(1997, 1, 1); - var endDate = new DateTime(1998, 1, 1); - - using var context = CreateContext(); - var actual - = await (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 }) - .ToArrayAsync(); - - Assert.Equal(25, actual.Length); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_multiple_line_query() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT * -FROM [Customers] -WHERE [City] = 'London'")) - .ToArrayAsync(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_composed_multiple_line_query() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT * -FROM [Customers]")) - .Where(c => c.City == "London") - .ToArrayAsync(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_with_parameters() - { - var city = "London"; - var contactTitle = "Sales Representative"; - - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, - contactTitle) - .ToArrayAsync(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_with_parameters_and_closure() - { - var city = "London"; - var contactTitle = "Sales Representative"; - - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) - .Where(c => c.ContactTitle == contactTitle) - .ToArrayAsync(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_cache_key_includes_query_string() - { - using var context = CreateContext(); - var actual = await context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) - .ToArrayAsync(); - - Assert.Equal(6, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - - actual = await context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")) - .ToArrayAsync(); - - Assert.Single(actual); - Assert.True(actual.All(c => c.City == "Seattle")); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters() - { - var city = "London"; - var contactTitle = "Sales Representative"; - var sql = "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"; - - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) - .ToArrayAsync(); - - Assert.Equal(3, actual.Length); - Assert.True(actual.All(c => c.City == "London")); - Assert.True(actual.All(c => c.ContactTitle == "Sales Representative")); - - city = "Madrid"; - contactTitle = "Accounting Manager"; - - actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) - .ToArrayAsync(); - - Assert.Equal(2, actual.Length); - Assert.True(actual.All(c => c.City == "Madrid")); - Assert.True(actual.All(c => c.ContactTitle == "Accounting Manager")); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_as_no_tracking_not_composed() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .AsNoTracking() - .ToArrayAsync(); - - Assert.Equal(91, actual.Length); - Assert.Empty(context.ChangeTracker.Entries()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_projection_not_composed() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Select( - c => new { c.CustomerID, c.City }) - .AsNoTracking() - .ToArrayAsync(); - - Assert.Equal(91, actual.Length); - Assert.Empty(context.ChangeTracker.Entries()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_include() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Include(c => c.Orders) - .ToArrayAsync(); - - Assert.Equal(830, actual.SelectMany(c => c.Orders).Count()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_queryable_simple_composed_include() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Include(c => c.Orders) - .Where(c => c.City == "London") - .ToArrayAsync(); - - Assert.Equal(46, actual.SelectMany(c => c.Orders).Count()); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_annotations_do_not_affect_successive_calls() - { - using var context = CreateContext(); - var actual = await context.Customers - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) - .ToArrayAsync(); - - Assert.Equal(14, actual.Length); - - actual = await context.Customers - .ToArrayAsync(); - - Assert.Equal(91, actual.Length); - } - - [ConditionalFact] - public virtual async Task FromSqlRaw_composed_with_nullable_predicate() - { - using var context = CreateContext(); - var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Where(c => c.ContactName == c.CompanyName) - .ToArrayAsync(); - - Assert.Empty(actual); - } - - [ConditionalFact] - public virtual async Task Include_does_not_close_user_opened_connection_for_empty_result() - { - Fixture.TestStore.CloseConnection(); - using (var context = CreateContext()) - { - var connection = context.Database.GetDbConnection(); - - Assert.Equal(ConnectionState.Closed, connection.State); - - context.Database.OpenConnection(); - - Assert.Equal(ConnectionState.Open, connection.State); - - var query = await context.Customers - .Include(v => v.Orders) - .Where(v => v.CustomerID == "MAMRFC") - .ToListAsync(); - - Assert.Empty(query); - Assert.Equal(ConnectionState.Open, connection.State); - - await context.Database.CloseConnectionAsync(); - - Assert.Equal(ConnectionState.Closed, connection.State); - } - - Fixture.TestStore.OpenConnection(); - } - - [ConditionalFact] - public virtual async Task Include_closed_connection_opened_by_it_when_buffering() - { - Fixture.TestStore.CloseConnection(); - using var context = CreateContext(); - var connection = context.Database.GetDbConnection(); - - Assert.Equal(ConnectionState.Closed, connection.State); - - var query = await context.Customers - .Include(v => v.Orders) - .Where(v => v.CustomerID == "ALFKI") - .ToListAsync(); - - Assert.NotEmpty(query); - Assert.Equal(ConnectionState.Closed, connection.State); - } - - private string NormalizeDelimitersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimitersInRawString(sql); - - private FormattableString NormalizeDelimitersInInterpolatedString(FormattableString sql) - => Fixture.TestStore.NormalizeDelimitersInInterpolatedString(sql); - - protected NorthwindContext CreateContext() - => Fixture.CreateContext(); - } -} diff --git a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs index 8f3d6892d09..a2e18584f2c 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs @@ -2,14 +2,17 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.Utilities; using Xunit; // ReSharper disable FormatStringProblem @@ -32,349 +35,479 @@ protected FromSqlQueryTestBase(TFixture fixture) protected TFixture Fixture { get; } - [ConditionalFact] - public virtual void Bad_data_error_handling_invalid_cast_key() + 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) { using var context = CreateContext(); + var query = context.Set().FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductName] AS [ProductID], [ProductID] AS [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], [Discontinued] + FROM [Products]")); + Assert.Equal( CoreStrings.ErrorMaterializingPropertyInvalidCast("Product", "ProductID", typeof(int), typeof(string)), - Assert.Throws( - () => - context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductName] AS [ProductID], [ProductID] AS [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], [Discontinued] - FROM [Products]")) - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void Bad_data_error_handling_invalid_cast() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bad_data_error_handling_invalid_cast(bool async) { using var context = CreateContext(); + var query = context.Set().FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductID], [SupplierID] AS [UnitPrice], [ProductName], [SupplierID], [UnitsInStock], [Discontinued] + FROM [Products]")); + Assert.Equal( CoreStrings.ErrorMaterializingPropertyInvalidCast("Product", "UnitPrice", typeof(decimal?), typeof(int)), - Assert.Throws( - () => - context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductID], [SupplierID] AS [UnitPrice], [ProductName], [SupplierID], [UnitsInStock], [Discontinued] - FROM [Products]")) - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void Bad_data_error_handling_invalid_cast_projection() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bad_data_error_handling_invalid_cast_projection(bool async) { using var context = CreateContext(); + var query = context.Set().FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductID], [SupplierID] AS [UnitPrice], [ProductName], [UnitsInStock], [Discontinued] + FROM [Products]")) + .Select(p => p.UnitPrice); + Assert.Equal( RelationalStrings.ErrorMaterializingValueInvalidCast(typeof(decimal?), typeof(int)), - Assert.Throws( - () => - context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductID], [SupplierID] AS [UnitPrice], [ProductName], [UnitsInStock], [Discontinued] - FROM [Products]")) - .Select(p => p.UnitPrice) - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void Bad_data_error_handling_invalid_cast_no_tracking() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bad_data_error_handling_invalid_cast_no_tracking(bool async) { using var context = CreateContext(); + var query = context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductName] AS [ProductID], [ProductID] AS [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], [Discontinued] + FROM [Products]")).AsNoTracking(); + Assert.Equal( CoreStrings.ErrorMaterializingPropertyInvalidCast("Product", "ProductID", typeof(int), typeof(string)), - Assert.Throws( - () => - context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductName] AS [ProductID], [ProductID] AS [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], [Discontinued] - FROM [Products]")).AsNoTracking() - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void Bad_data_error_handling_null() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bad_data_error_handling_null(bool async) { using var context = CreateContext(); + var query = context.Set().FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] + FROM [Products]")); + Assert.Equal( RelationalStrings.ErrorMaterializingPropertyNullReference("Product", "Discontinued", typeof(bool)), - Assert.Throws( - () => - context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] - FROM [Products]")) - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void Bad_data_error_handling_null_projection() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bad_data_error_handling_null_projection(bool async) { using var context = CreateContext(); + var query = context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] + FROM [Products]")) + .Select(p => p.Discontinued); + Assert.Equal( RelationalStrings.ErrorMaterializingValueNullReference(typeof(bool)), - Assert.Throws( - () => - context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] - FROM [Products]")) - .Select(p => p.Discontinued) - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void Bad_data_error_handling_null_no_tracking() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bad_data_error_handling_null_no_tracking(bool async) { using var context = CreateContext(); + var query = context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString( + @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] + FROM [Products]")).AsNoTracking(); + Assert.Equal( RelationalStrings.ErrorMaterializingPropertyNullReference("Product", "Discontinued", typeof(bool)), - Assert.Throws( - () => - context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString( - @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] - FROM [Products]")).AsNoTracking() - .ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple(bool async) { using var context = CreateContext(); - var actual = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) - .ToArray(); + 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()); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_columns_out_of_order() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString( - "SELECT [Region], [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) - .ToArray(); + "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()); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_columns_out_of_order_and_extra_columns() + [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 actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString( - "SELECT [Region], [PostalCode], [PostalCode] AS [Foo], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) - .ToArray(); + "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()); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_columns_out_of_order_and_not_enough_columns_throws() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order_and_not_enough_columns_throws(bool async) { using var context = CreateContext(); + var query = context.Set().FromSqlRaw( + NormalizeDelimitersInRawString( + "SELECT [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")); + Assert.Equal( RelationalStrings.FromSqlMissingColumn("Region"), - Assert.Throws( - () => context.Set().FromSqlRaw( - NormalizeDelimitersInRawString( - "SELECT [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) - .ToArray() - ).Message); + (async + ? await Assert.ThrowsAsync(() => query.ToListAsync()) + : Assert.Throws(() => query.ToList())).Message); } - [ConditionalFact] - public virtual string FromSqlRaw_queryable_composed() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed(bool async) { using var context = CreateContext(); - var queryable = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Where(c => c.ContactName.Contains("z")); - var queryString = queryable.ToQueryString(); + var queryString = query.ToQueryString(); - var actual = queryable.ToArray(); + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(14, actual.Length); return queryString; } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_composed_after_removing_whitespaces() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed_after_removing_whitespaces(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString( _eol + " " + _eol + _eol + _eol + "SELECT" + _eol + "* FROM [Customers]")) - .Where(c => c.ContactName.Contains("z")) - .ToArray(); + .Where(c => c.ContactName.Contains("z")); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(14, actual.Length); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_composed_compiled() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed_compiled(bool async) { - var query = EF.CompileQuery( - (NorthwindContext context) => context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Where(c => c.ContactName.Contains("z"))); + if (async) + { + var query = EF.CompileAsyncQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Where(c => c.ContactName.Contains("z"))); - using (var context = CreateContext()) + using (var context = CreateContext()) + { + var actual = await query(context).ToListAsync(); + + Assert.Equal(14, actual.Count); + } + } + else { - var actual = query(context).ToArray(); + var query = EF.CompileQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .Where(c => c.ContactName.Contains("z"))); - Assert.Equal(14, actual.Length); + using (var context = CreateContext()) + { + var actual = query(context).ToArray(); + + Assert.Equal(14, actual.Length); + } } } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_composed_compiled_with_parameter() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed_compiled_with_parameter(bool async) { - var query = EF.CompileQuery( - (NorthwindContext context) => context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), "CONSH") - .Where(c => c.ContactName.Contains("z"))); - - using (var context = CreateContext()) + if (async) { - var actual = query(context).ToArray(); - - Assert.Single(actual); + var query = EF.CompileAsyncQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), "CONSH") + .Where(c => c.ContactName.Contains("z"))); + + using (var context = CreateContext()) + { + var actual = await query(context).ToListAsync(); + + Assert.Single(actual); + } + } + else + { + var query = EF.CompileQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), "CONSH") + .Where(c => c.ContactName.Contains("z"))); + + using (var context = CreateContext()) + { + var actual = query(context).ToArray(); + + Assert.Single(actual); + } } } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_composed_compiled_with_DbParameter() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed_compiled_with_DbParameter(bool async) { - var query = EF.CompileQuery( - (NorthwindContext context) => context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @customer"), - CreateDbParameter("customer", "CONSH")) - .Where(c => c.ContactName.Contains("z"))); - - using (var context = CreateContext()) + if (async) { - var actual = query(context).ToArray(); - - Assert.Single(actual); + var query = EF.CompileAsyncQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @customer"), + CreateDbParameter("customer", "CONSH")) + .Where(c => c.ContactName.Contains("z"))); + + using (var context = CreateContext()) + { + var actual = await query(context).ToListAsync(); + + Assert.Single(actual); + } + } + else + { + var query = EF.CompileQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @customer"), + CreateDbParameter("customer", "CONSH")) + .Where(c => c.ContactName.Contains("z"))); + + using (var context = CreateContext()) + { + var actual = query(context).ToArray(); + + Assert.Single(actual); + } } } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_composed_compiled_with_nameless_DbParameter() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed_compiled_with_nameless_DbParameter(bool async) { - var query = EF.CompileQuery( - (NorthwindContext context) => context.Set() - .FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), - CreateDbParameter(null, "CONSH")) - .Where(c => c.ContactName.Contains("z"))); - - using (var context = CreateContext()) + if (async) { - var actual = query(context).ToArray(); - - Assert.Single(actual); + var query = EF.CompileAsyncQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), + CreateDbParameter(null, "CONSH")) + .Where(c => c.ContactName.Contains("z"))); + + using (var context = CreateContext()) + { + var actual = await query(context).ToListAsync(); + + Assert.Single(actual); + } + } + else + { + var query = EF.CompileQuery( + (NorthwindContext context) => context.Set() + .FromSqlRaw( + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), + CreateDbParameter(null, "CONSH")) + .Where(c => c.ContactName.Contains("z"))); + + using (var context = CreateContext()) + { + var actual = query(context).ToArray(); + + Assert.Single(actual); + } } } - [ConditionalFact] - public virtual void FromSqlRaw_composed_contains() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_composed_contains(bool async) { using var context = CreateContext(); - var actual - = (from c in context.Set() - where context.Orders.FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) - .Select(o => o.CustomerID) - .Contains(c.CustomerID) - select c) - .ToArray(); + 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); } - [ConditionalFact] - public virtual void FromSqlRaw_composed_contains2() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_composed_contains2(bool async) { using var context = CreateContext(); - var actual - = (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) - .ToArray(); + 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); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_multiple_composed() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_multiple_composed(bool async) { using var context = CreateContext(); - var actual - = (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 }) - .ToArray(); + 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); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_multiple_composed_with_closure_parameters() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async 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 actual - = (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 }) - .ToArray(); + 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); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters(bool async) { var city = "London"; var startDate = new DateTime(1997, 1, 1); var endDate = new DateTime(1998, 1, 1); using var context = CreateContext(); - var actual - = (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 }) - .ToArray(); + var 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 }; + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(25, actual.Length); @@ -382,129 +515,159 @@ from o in context.Set().FromSqlRaw( startDate = new DateTime(1998, 4, 1); endDate = new DateTime(1998, 5, 1); - actual - = (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 }) - .ToArray(); + 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); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_multiple_line_query() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_multiple_line_query(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString( @"SELECT * FROM [Customers] -WHERE [City] = 'London'")) - .ToArray(); +WHERE [City] = 'London'")); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(6, actual.Length); Assert.True(actual.All(c => c.City == "London")); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_composed_multiple_line_query() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_composed_multiple_line_query(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString( @"SELECT * FROM [Customers]")) - .Where(c => c.City == "London") - .ToArray(); + .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")); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_with_parameters() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_with_parameters(bool async) { var city = "London"; var contactTitle = "Sales Representative"; using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, - contactTitle) - .ToArray(); + 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")); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_with_parameters_inline() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_with_parameters_inline(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), "London", - "Sales Representative") - .ToArray(); + "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")); } - [ConditionalFact] - public virtual void FromSqlInterpolated_queryable_with_parameters_interpolated() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlInterpolated_queryable_with_parameters_interpolated(bool async) { var city = "London"; var contactTitle = "Sales Representative"; using var context = CreateContext(); - var actual = context.Set().FromSqlInterpolated( + var query = context.Set().FromSqlInterpolated( NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Customers] WHERE [City] = {city} AND [ContactTitle] = {contactTitle}")) - .ToArray(); + $"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")); } - [ConditionalFact] - public virtual void FromSqlInterpolated_queryable_with_parameters_inline_interpolated() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlInterpolated_queryable_with_parameters_inline_interpolated(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlInterpolated( + var query = context.Set().FromSqlInterpolated( NormalizeDelimitersInInterpolatedString( - $"SELECT * FROM [Customers] WHERE [City] = {"London"} AND [ContactTitle] = {"Sales Representative"}")) - .ToArray(); + $"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")); } - [ConditionalFact] - public virtual void FromSqlInterpolated_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlInterpolated_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated(bool async) { var city = "London"; var startDate = new DateTime(1997, 1, 1); var endDate = new DateTime(1998, 1, 1); using var context = CreateContext(); - var actual - = (from c in context.Set().FromSqlRaw( + var 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 }) - .ToArray(); + 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); @@ -512,46 +675,57 @@ from o in context.Set().FromSqlInterpolated( startDate = new DateTime(1998, 4, 1); endDate = new DateTime(1998, 5, 1); - actual + 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 }) - .ToArray(); + select new { c, o }); + + actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Single(actual); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_with_null_parameter() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_with_null_parameter(bool async) { uint? reportsTo = null; using var context = CreateContext(); - var actual = context.Set().FromSqlRaw( + 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) - .ToArray(); + "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); } - [ConditionalFact] - public virtual string FromSqlRaw_queryable_with_parameters_and_closure() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_with_parameters_and_closure(bool async) { var city = "London"; var contactTitle = "Sales Representative"; using var context = CreateContext(); - var queryable = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) .Where(c => c.ContactTitle == contactTitle); - var queryString = queryable.ToQueryString(); - var actual = queryable.ToArray(); + var queryString = query.ToQueryString(); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(3, actual.Length); Assert.True(actual.All(c => c.City == "London")); @@ -560,35 +734,46 @@ public virtual string FromSqlRaw_queryable_with_parameters_and_closure() return queryString; } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_cache_key_includes_query_string() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_cache_key_includes_query_string(bool async) { using var context = CreateContext(); - var actual = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) - .ToArray(); + 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")); - actual = context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")) - .ToArray(); + query = context.Set() + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")); + + actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Single(actual); Assert.True(actual.All(c => c.City == "Seattle")); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters(bool async) { var city = "London"; var contactTitle = "Sales Representative"; var sql = "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"; using var context = CreateContext(); - var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) - .ToArray(); + 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")); @@ -597,32 +782,40 @@ public virtual void FromSqlRaw_queryable_with_parameters_cache_key_includes_para city = "Madrid"; contactTitle = "Accounting Manager"; - actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) - .ToArray(); + 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")); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_as_no_tracking_not_composed() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_as_no_tracking_not_composed(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .AsNoTracking() - .ToArray(); + var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + .AsNoTracking(); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(91, actual.Length); Assert.Empty(context.ChangeTracker.Entries()); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_projection_composed() + [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 actual = context.Set().FromSqlRaw( + var query = context.Set().FromSqlRaw( NormalizeDelimitersInRawString( @"SELECT * FROM [Products] @@ -630,92 +823,122 @@ WHERE [Discontinued] <> " + boolMapping.GenerateSqlLiteral(true) + @" AND (([UnitsInStock] + [UnitsOnOrder]) < [ReorderLevel])")) - .Select(p => p.ProductName) - .ToArray(); + .Select(p => p.ProductName); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(2, actual.Length); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_include() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_include(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Include(c => c.Orders) - .ToArray(); + 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()); } - [ConditionalFact] - public virtual void FromSqlRaw_queryable_simple_composed_include() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_queryable_simple_composed_include(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + var query = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Include(c => c.Orders) - .Where(c => c.City == "London") - .ToArray(); + .Where(c => c.City == "London"); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(46, actual.SelectMany(c => c.Orders).Count()); } - [ConditionalFact] - public virtual void FromSqlRaw_annotations_do_not_affect_successive_calls() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_annotations_do_not_affect_successive_calls(bool async) { using var context = CreateContext(); - var actual = context.Customers - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) - .ToArray(); + var query = context.Customers + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(14, actual.Length); - actual = context.Customers - .ToArray(); + query = context.Customers; + actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(91, actual.Length); } - [ConditionalFact] - public virtual void FromSqlRaw_composed_with_nullable_predicate() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_composed_with_nullable_predicate(bool async) { using var context = CreateContext(); - var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) - .Where(c => c.ContactName == c.CompanyName) - .ToArray(); + 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); } - [ConditionalFact] - public virtual void FromSqlRaw_with_dbParameter() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_with_dbParameter(bool async) { using var context = CreateContext(); var parameter = CreateDbParameter("@city", "London"); - var actual = context.Customers.FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter) - .ToArray(); + 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")); } - [ConditionalFact] - public virtual void FromSqlRaw_with_dbParameter_without_name_prefix() + [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 actual = context.Customers.FromSqlRaw( - NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter) - .ToArray(); + 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")); } - [ConditionalFact] - public virtual void FromSqlRaw_with_dbParameter_mixed() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_with_dbParameter_mixed(bool async) { using var context = CreateContext(); var city = "London"; @@ -723,10 +946,13 @@ public virtual void FromSqlRaw_with_dbParameter_mixed() var titleParameter = CreateDbParameter("@title", title); - var actual = context.Customers.FromSqlRaw( + var query = context.Customers.FromSqlRaw( NormalizeDelimitersInRawString( - "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = @title"), city, titleParameter) - .ToArray(); + "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")); @@ -734,18 +960,22 @@ public virtual void FromSqlRaw_with_dbParameter_mixed() var cityParameter = CreateDbParameter("@city", city); - actual = context.Customers.FromSqlRaw( + query = context.Customers.FromSqlRaw( NormalizeDelimitersInRawString( - "SELECT * FROM [Customers] WHERE [City] = @city AND [ContactTitle] = {1}"), cityParameter, title) - .ToArray(); + "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")); } - [ConditionalFact] - public virtual void Include_does_not_close_user_opened_connection_for_empty_result() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Include_does_not_close_user_opened_connection_for_empty_result(bool async) { Fixture.TestStore.CloseConnection(); using (var context = CreateContext()) @@ -760,8 +990,11 @@ public virtual void Include_does_not_close_user_opened_connection_for_empty_resu var query = context.Customers .Include(v => v.Orders) - .Where(v => v.CustomerID == "MAMRFC") - .ToList(); + .Where(v => v.CustomerID == "MAMRFC"); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Empty(query); Assert.Equal(ConnectionState.Open, connection.State); @@ -774,8 +1007,9 @@ public virtual void Include_does_not_close_user_opened_connection_for_empty_resu Fixture.TestStore.OpenConnection(); } - [ConditionalFact] - public virtual void FromSqlRaw_with_db_parameters_called_multiple_times() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_with_db_parameters_called_multiple_times(bool async) { using var context = CreateContext(); var parameter = CreateDbParameter("@id", "ALFKI"); @@ -784,18 +1018,23 @@ public virtual void FromSqlRaw_with_db_parameters_called_multiple_times() NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @id"), parameter); // ReSharper disable PossibleMultipleEnumeration - var result1 = query.ToList(); + var result1 = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Single(result1); - var result2 = query.ToList(); + var result2 = async + ? await query.ToArrayAsync() + : query.ToArray(); // ReSharper restore PossibleMultipleEnumeration Assert.Single(result2); } - [ConditionalFact] - public virtual void FromSqlRaw_with_SelectMany_and_include() + [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() @@ -805,7 +1044,9 @@ from c2 in context.Set().FromSqlRaw( .Include(c => c.Orders) select new { c1, c2 }; - var result = query.ToList(); + var result = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Single(result); var customers1 = result.Select(r => r.c1); @@ -821,8 +1062,9 @@ from c2 in context.Set().FromSqlRaw( } } - [ConditionalFact] - public virtual void FromSqlRaw_with_join_and_include() + [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() @@ -833,7 +1075,9 @@ join o in context.Set().FromSqlRaw( on c.CustomerID equals o.CustomerID select new { c, o }; - var result = query.ToList(); + var result = async + ? await query.ToListAsync() + : query.ToList(); Assert.Equal(6, result.Count); @@ -844,8 +1088,9 @@ on c.CustomerID equals o.CustomerID } } - [ConditionalFact] - public virtual void Include_closed_connection_opened_by_it_when_buffering() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Include_closed_connection_opened_by_it_when_buffering(bool async) { Fixture.TestStore.CloseConnection(); using var context = CreateContext(); @@ -855,45 +1100,57 @@ public virtual void Include_closed_connection_opened_by_it_when_buffering() var query = context.Customers .Include(v => v.Orders) - .Where(v => v.CustomerID == "ALFKI") - .ToList(); + .Where(v => v.CustomerID == "ALFKI"); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.NotEmpty(query); Assert.Equal(ConnectionState.Closed, connection.State); } - [ConditionalFact] - public virtual void FromSqlInterpolated_with_inlined_db_parameter() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlInterpolated_with_inlined_db_parameter(bool async) { using var context = CreateContext(); var parameter = CreateDbParameter("@somename", "ALFKI"); - var actual = context.Customers + var query = context.Customers .FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")) - .ToList(); + 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")); } - [ConditionalFact] - public virtual void FromSqlInterpolated_with_inlined_db_parameter_without_name_prefix() + [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 actual = context.Customers + var query = context.Customers .FromSqlInterpolated( - NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")) - .ToList(); + 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")); } - [ConditionalFact] - public virtual void FromSqlInterpolated_parameterization_issue_12213() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlInterpolated_parameterization_issue_12213(bool async) { using var context = CreateContext(); var min = 10300; @@ -902,12 +1159,18 @@ public virtual void FromSqlInterpolated_parameterization_issue_12213() var query1 = context.Orders .FromSqlInterpolated(NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Orders] WHERE [OrderID] >= {min}")) .Select(i => i.OrderID); - query1.ToList(); + + var actual1 = async + ? await query1.ToArrayAsync() + : query1.ToArray(); var query2 = context.Orders .Where(o => o.OrderID <= max && query1.Contains(o.OrderID)) .Select(o => o.OrderID); - query2.ToList(); + + var actual2 = async + ? await query2.ToArrayAsync() + : query2.ToArray(); var query3 = context.Orders .Where( @@ -918,93 +1181,247 @@ public virtual void FromSqlInterpolated_parameterization_issue_12213() .Select(i => i.OrderID) .Contains(o.OrderID)) .Select(o => o.OrderID); - query3.ToList(); + + var actual3 = async + ? await query3.ToArrayAsync() + : query3.ToArray(); } - [ConditionalFact] - public virtual void FromSqlRaw_does_not_parameterize_interpolated_string() + [ConditionalTheory] + [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) - .ToList(); + NormalizeDelimitersInRawString($"SELECT * FROM [{tableName}] WHERE [OrderID] < {{0}}"), max); - Assert.Equal(2, query.Count); + var actual = async + ? await query.ToListAsync() + : query.ToList(); + + Assert.Equal(2, actual.Count); } - [ConditionalFact] - public virtual void Entity_equality_through_fromsql() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Entity_equality_through_fromsql(bool async) { using var context = CreateContext(); - var actual = context.Set() + var query = context.Set() .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) - .Where(o => o.Customer == new Customer { CustomerID = "VINET" }) - .ToArray(); + .Where(o => o.Customer == new Customer { CustomerID = "VINET" }); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(5, actual.Length); } - [ConditionalFact] - public virtual void FromSqlRaw_with_set_operation() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlRaw_with_set_operation(bool async) { using var context = CreateContext(); - var actual = context.Set() + var query = context.Set() .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) .Concat( context.Set() - .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Berlin'"))) - .ToArray(); + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Berlin'"))); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.Equal(7, actual.Length); } - [ConditionalFact] - public virtual void Keyless_entity_with_all_nulls() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Keyless_entity_with_all_nulls(bool async) { using var context = CreateContext(); - var actual = context.Set() + var query = context.Set() .FromSqlRaw(NormalizeDelimitersInRawString("SELECT NULL AS [CustomerID] FROM [Customers] WHERE [City] = 'Berlin'")) - .IgnoreQueryFilters() - .ToArray(); + .IgnoreQueryFilters(); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.NotNull(Assert.Single(actual)); } - [ConditionalFact] - public virtual void Line_endings_after_Select() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Line_endings_after_Select(bool async) { using var context = CreateContext(); - var actual = context.Set() + var query = context.Set() .FromSqlRaw(NormalizeDelimitersInRawString("SELECT" + Environment.NewLine + "* FROM [Customers]")) - .Where(e => e.City == "Seattle") - .ToArray(); + .Where(e => e.City == "Seattle"); + + var actual = async + ? await query.ToArrayAsync() + : query.ToArray(); Assert.NotNull(actual); } - [ConditionalFact] - public virtual void FromSql_with_db_parameter_in_split_query() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSql_with_db_parameter_in_split_query(bool async) { using var context = CreateContext(); - var actual = context.Set() + var query = context.Set() .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), CreateDbParameter("customerID", "ALFKI")) .Include(e => e.Orders) .ThenInclude(o => o.OrderDetails) - .AsSplitQuery() - .ToArray(); + .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()); + } + + [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( + @"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); + } + + [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 + .FromSqlRaw( + @"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); + } + + [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 + .FromSqlRaw( + @"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); + } + + [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 + .FromSqlRaw( + @"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); + + query = context.Orders.Where( + o => + context.Customers + .FromSqlRaw( + @"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); + } + protected string NormalizeDelimitersInRawString(string sql) => Fixture.TestStore.NormalizeDelimitersInRawString(sql); diff --git a/test/EFCore.Relational.Specification.Tests/Query/NorthwindAsyncSimpleQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NorthwindAsyncSimpleQueryRelationalTestBase.cs deleted file mode 100644 index a931ffd8e0a..00000000000 --- a/test/EFCore.Relational.Specification.Tests/Query/NorthwindAsyncSimpleQueryRelationalTestBase.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.EntityFrameworkCore.TestUtilities; - -namespace Microsoft.EntityFrameworkCore.Query -{ - public abstract class NorthwindAsyncSimpleQueryRelationalTestBase : NorthwindAsyncSimpleQueryTestBase - where TFixture : NorthwindQueryFixtureBase, new() - { - protected NorthwindAsyncSimpleQueryRelationalTestBase(TFixture fixture) - : base(fixture) - { - } - - protected virtual bool CanExecuteQueryString - => false; - - protected override QueryAsserter CreateQueryAsserter(TFixture fixture) - => new RelationalQueryAsserter( - fixture, RewriteExpectedQueryExpression, RewriteServerQueryExpression, canExecuteQueryString: CanExecuteQueryString); - } -} diff --git a/test/EFCore.Specification.Tests/Query/NorthwindAsyncSimpleQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindAsyncSimpleQueryTestBase.cs deleted file mode 100644 index a4e48c17cb8..00000000000 --- a/test/EFCore.Specification.Tests/Query/NorthwindAsyncSimpleQueryTestBase.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.TestModels.Northwind; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; - -// ReSharper disable InconsistentNaming -// ReSharper disable ConvertToExpressionBodyWhenPossible -// ReSharper disable AccessToDisposedClosure -// ReSharper disable AccessToModifiedClosure -// ReSharper disable StringStartsWithIsCultureSpecific -// ReSharper disable StringEndsWithIsCultureSpecific -namespace Microsoft.EntityFrameworkCore.Query -{ - public abstract class NorthwindAsyncSimpleQueryTestBase : QueryTestBase - where TFixture : NorthwindQueryFixtureBase, new() - { - protected NorthwindAsyncSimpleQueryTestBase(TFixture fixture) - : base(fixture) - { - } - - protected NorthwindContext CreateContext() - => Fixture.CreateContext(); - - [ConditionalFact] - public virtual async Task Query_backed_by_database_view() - { - using var context = CreateContext(); - var results = await context.Set().ToArrayAsync(); - - Assert.Equal(69, results.Length); - } - - [ConditionalFact] - public virtual async Task ToList_context_subquery_deadlock_issue() - { - using var context = CreateContext(); - var _ = await context.Customers - .Select( - c => new - { - c.CustomerID, - Posts = context.Orders.Where(o => o.CustomerID == c.CustomerID) - .Select( - m => new { m.CustomerID }) - .ToList() - }) - .ToListAsync(); - } - - [ConditionalFact] - public virtual async Task ToArray_on_nav_subquery_in_projection() - { - using var context = CreateContext(); - var results - = await context.Customers.Select( - c => new { Orders = c.Orders.ToArray() }) - .ToListAsync(); - - Assert.Equal(830, results.SelectMany(a => a.Orders).ToList().Count); - } - - [ConditionalFact] - public virtual async Task ToArray_on_nav_subquery_in_projection_nested() - { - using var context = CreateContext(); - var results - = await context.Customers.Select( - c => new - { - Orders = c.Orders.Select( - o => new { OrderDetails = o.OrderDetails.ToArray() }) - .ToArray() - }) - .ToListAsync(); - - Assert.Equal(2155, results.SelectMany(a => a.Orders.SelectMany(o => o.OrderDetails)).ToList().Count); - } - - [ConditionalFact] - public virtual async Task ToList_on_nav_subquery_in_projection() - { - using var context = CreateContext(); - var results - = await context.Customers.Select( - c => new { Orders = c.Orders.ToList() }) - .ToListAsync(); - - Assert.Equal(830, results.SelectMany(a => a.Orders).ToList().Count); - } - - [ConditionalFact] - public virtual async Task ToList_on_nav_subquery_with_predicate_in_projection() - { - using var context = CreateContext(); - var results - = await context.Customers.Select( - c => new { Orders = c.Orders.Where(o => o.OrderID > 10).ToList() }) - .ToListAsync(); - - Assert.Equal(830, results.SelectMany(a => a.Orders).ToList().Count); - } - - [ConditionalFact] - public virtual async Task ToListAsync_can_be_canceled() - { - for (var i = 0; i < 10; i++) - { - // without fix, this usually throws within 2 or three iterations - - using var context = CreateContext(); - var tokenSource = new CancellationTokenSource(); - var query = context.Employees.AsNoTracking().ToListAsync(tokenSource.Token); - tokenSource.Cancel(); - List result = null; - Exception exception = null; - try - { - result = await query; - } - catch (Exception e) - { - exception = e; - } - - if (exception != null) - { - Assert.Null(result); - } - else - { - Assert.Equal(9, result.Count); - } - } - } - - [ConditionalFact(Skip = "Issue #17019")] - public virtual async Task Mixed_sync_async_query() - { - using var context = CreateContext(); - var results - = (await context.Customers - .Select( - c => new { c.CustomerID, Orders = context.Orders.Where(o => o.Customer.CustomerID == c.CustomerID) }) - .ToListAsync()) - .Select( - x => new - { - Orders = x.Orders - .GroupJoin( - new[] { "ALFKI" }, y => x.CustomerID, y => y, (h, id) => new { h.Customer }) - }) - .ToList(); - - Assert.Equal(830, results.SelectMany(r => r.Orders).ToList().Count); - } - - [ConditionalFact] - public virtual async Task LoadAsync_should_track_results() - { - using var context = CreateContext(); - await context.Customers.LoadAsync(); - - Assert.Equal(91, context.ChangeTracker.Entries().Count()); - } - - protected virtual async Task Single_Predicate_Cancellation_test(CancellationToken cancellationToken) - { - using var ctx = CreateContext(); - var result = await ctx.Customers.SingleAsync(c => c.CustomerID == "ALFKI", cancellationToken); - - Assert.Equal("ALFKI", result.CustomerID); - } - - [ConditionalFact] - public virtual async Task Mixed_sync_async_in_query_cache() - { - using var context = CreateContext(); - Assert.Equal(91, context.Customers.AsNoTracking().ToList().Count); - Assert.Equal(91, (await context.Customers.AsNoTracking().ToListAsync()).Count); - } - - [ConditionalFact] - public virtual async Task Throws_on_concurrent_query_list() - { - using var context = CreateContext(); - using var synchronizationEvent = new ManualResetEventSlim(false); - using var blockingSemaphore = new SemaphoreSlim(0); - var blockingTask = Task.Run( - () => - { - try - { - context.Customers.Select( - c => Process(c, synchronizationEvent, blockingSemaphore)).ToList(); - } - finally - { - synchronizationEvent.Set(); - } - }); - - var throwingTask = Task.Run( - async () => - { - synchronizationEvent.Wait(TimeSpan.FromMinutes(5)); - - Assert.Equal( - CoreStrings.ConcurrentMethodInvocation, - (await Assert.ThrowsAsync( - () => context.Customers.ToListAsync())).Message); - }); - - await throwingTask; - - blockingSemaphore.Release(1); - - await blockingTask; - } - - [ConditionalFact] - public virtual async Task Throws_on_concurrent_query_first() - { - using var context = CreateContext(); - using var synchronizationEvent = new ManualResetEventSlim(false); - using var blockingSemaphore = new SemaphoreSlim(0); - var blockingTask = Task.Run( - () => - { - try - { - context.Customers.Select( - c => Process(c, synchronizationEvent, blockingSemaphore)).ToList(); - } - finally - { - synchronizationEvent.Set(); - } - }); - - var throwingTask = Task.Run( - async () => - { - synchronizationEvent.Wait(TimeSpan.FromMinutes(5)); - - Assert.Equal( - CoreStrings.ConcurrentMethodInvocation, - (await Assert.ThrowsAsync( - () => context.Customers.FirstAsync())).Message); - }); - - await throwingTask; - - blockingSemaphore.Release(1); - - await blockingTask; - } - - private static Customer Process(Customer c, ManualResetEventSlim e, SemaphoreSlim s) - { - e.Set(); - s.Wait(TimeSpan.FromMinutes(5)); - s.Release(1); - return c; - } - - // Set Operations - - [ConditionalFact] - public virtual async Task Concat_dbset() - { - using var context = CreateContext(); - var query = await context.Set() - .Where(c => c.City == "México D.F.") - .Concat( - context.Set()) - .ToListAsync(); - - Assert.Equal(96, query.Count); - } - - [ConditionalFact] - public virtual async Task Concat_simple() - { - using var context = CreateContext(); - var query = await context.Set() - .Where(c => c.City == "México D.F.") - .Concat( - context.Set() - .Where(s => s.ContactTitle == "Owner")) - .ToListAsync(); - - Assert.Equal(22, query.Count); - } - - [ConditionalFact] - public virtual async Task Concat_non_entity() - { - using var context = CreateContext(); - var query = await context.Set() - .Where(c => c.City == "México D.F.") - .Select(c => c.CustomerID) - .Concat( - context.Set() - .Where(s => s.ContactTitle == "Owner") - .Select(c => c.CustomerID)) - .ToListAsync(); - - Assert.Equal(22, query.Count); - } - - [ConditionalFact] - public virtual async Task Except_non_entity() - { - using var context = CreateContext(); - var query = await context.Set() - .Where(s => s.ContactTitle == "Owner") - .Select(c => c.CustomerID) - .Except( - context.Set() - .Where(c => c.City == "México D.F.") - .Select(c => c.CustomerID)) - .ToListAsync(); - - Assert.Equal(14, query.Count); - } - - [ConditionalFact] - public virtual async Task Intersect_non_entity() - { - using var context = CreateContext(); - var query = await context.Set() - .Where(c => c.City == "México D.F.") - .Select(c => c.CustomerID) - .Intersect( - context.Set() - .Where(s => s.ContactTitle == "Owner") - .Select(c => c.CustomerID)) - .ToListAsync(); - - Assert.Equal(3, query.Count); - } - - [ConditionalFact] - public virtual async Task Union_non_entity() - { - using var context = CreateContext(); - var query = await context.Set() - .Where(s => s.ContactTitle == "Owner") - .Select(c => c.CustomerID) - .Union( - context.Set() - .Where(c => c.City == "México D.F.") - .Select(c => c.CustomerID)) - .ToListAsync(); - - Assert.Equal(19, query.Count); - } - - [ConditionalFact] - public virtual async Task Select_bitwise_or() - { - using var context = CreateContext(); - var query = await context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" }).ToListAsync(); - - Assert.All(query.Take(2), t => Assert.True(t.Value)); - Assert.All(query.Skip(2), t => Assert.False(t.Value)); - } - - [ConditionalFact] - public virtual async Task Select_bitwise_or_multiple() - { - using var context = CreateContext(); - var query = await context.Customers.OrderBy(c => c.CustomerID) - .Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" | c.CustomerID == "ANTON" }) - .ToListAsync(); - - Assert.All(query.Take(3), t => Assert.True(t.Value)); - Assert.All(query.Skip(3), t => Assert.False(t.Value)); - } - - [ConditionalFact] - public virtual async Task Select_bitwise_and() - { - using var context = CreateContext(); - var query = await context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" }).ToListAsync(); - - Assert.All(query, t => Assert.False(t.Value)); - } - - [ConditionalFact] - public virtual async Task Select_bitwise_and_or() - { - using var context = CreateContext(); - var query = await context.Customers.OrderBy(c => c.CustomerID) - .Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" | c.CustomerID == "ANTON" }) - .ToListAsync(); - - Assert.All(query.Where(c => c.CustomerID != "ANTON"), t => Assert.False(t.Value)); - } - - [ConditionalFact] - public virtual async Task Select_bitwise_or_with_logical_or() - { - using var context = CreateContext(); - var query = await context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" || c.CustomerID == "ANTON" }) - .ToListAsync(); - - Assert.All(query.Take(3), t => Assert.True(t.Value)); - Assert.All(query.Skip(3), t => Assert.False(t.Value)); - } - - [ConditionalFact] - public virtual async Task Select_bitwise_and_with_logical_and() - { - using var context = CreateContext(); - var query = await context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" && c.CustomerID == "ANTON" }) - .ToListAsync(); - - Assert.All(query, t => Assert.False(t.Value)); - } - } -} diff --git a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs index 3863f77a95e..a009b1b993e 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs @@ -3462,8 +3462,9 @@ orderby o.OrderID Assert.Single(orders); } - [ConditionalFact(Skip = "Issue#17019")] - public virtual void Throws_on_concurrent_query_list() + [ConditionalTheory(Skip = "Issue#17019")] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Throws_on_concurrent_query_list(bool async) { using var context = CreateContext(); context.Database.EnsureCreatedResiliently(); @@ -3485,24 +3486,26 @@ public virtual void Throws_on_concurrent_query_list() }); var throwingTask = Task.Run( - () => + async () => { synchronizationEvent.Wait(TimeSpan.FromMinutes(5)); Assert.Equal( CoreStrings.ConcurrentMethodInvocation, - Assert.Throws( - () => context.Customers.ToList()).Message); + (async + ? await Assert.ThrowsAsync(() => context.Customers.ToListAsync()) + : Assert.Throws(() => context.Customers.ToList())).Message); }); - throwingTask.Wait(TimeSpan.FromMinutes(5)); + await throwingTask; blockingSemaphore.Release(1); - blockingTask.Wait(TimeSpan.FromMinutes(5)); + await blockingTask; } - [ConditionalFact(Skip = "Issue#17019")] - public virtual void Throws_on_concurrent_query_first() + [ConditionalTheory(Skip = "Issue#17019")] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Throws_on_concurrent_query_first(bool async) { using var context = CreateContext(); context.Database.EnsureCreatedResiliently(); @@ -3524,20 +3527,21 @@ public virtual void Throws_on_concurrent_query_first() }); var throwingTask = Task.Run( - () => + async () => { synchronizationEvent.Wait(TimeSpan.FromMinutes(5)); Assert.Equal( CoreStrings.ConcurrentMethodInvocation, - Assert.Throws( - () => context.Customers.First()).Message); + (async + ? await Assert.ThrowsAsync(() => context.Customers.FirstAsync()) + : Assert.Throws(() => context.Customers.First())).Message); }); - throwingTask.Wait(TimeSpan.FromMinutes(5)); + await throwingTask; blockingSemaphore.Release(1); - blockingTask.Wait(TimeSpan.FromMinutes(5)); + await blockingTask; } private static Customer Process(Customer c, ManualResetEventSlim e, SemaphoreSlim s) @@ -3726,50 +3730,46 @@ public virtual Task String_concat_with_navigation2(bool async) ss => ss.Set().Select(o => o.Customer.City + " " + o.Customer.City)); } - [ConditionalFact] - public virtual void Select_bitwise_or() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_bitwise_or(bool async) { - using var context = CreateContext(); - var query = context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" }).ToList(); - - Assert.All(query.Take(2), t => Assert.True(t.Value)); - Assert.All(query.Skip(2), t => Assert.False(t.Value)); + return AssertQuery( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Select( + c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" })); } - [ConditionalFact] - public virtual void Select_bitwise_or_multiple() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_bitwise_or_multiple(bool async) { - using var context = CreateContext(); - var query = context.Customers.OrderBy(c => c.CustomerID) - .Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" | c.CustomerID == "ANTON" }) - .ToList(); - - Assert.All(query.Take(3), t => Assert.True(t.Value)); - Assert.All(query.Skip(3), t => Assert.False(t.Value)); + return AssertQuery( + async, + ss => ss.Set().OrderBy(c => c.CustomerID) + .Select( + c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" | c.CustomerID == "ANTON" })); } - [ConditionalFact] - public virtual void Select_bitwise_and() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_bitwise_and(bool async) { - using var context = CreateContext(); - var query = context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" }).ToList(); - - Assert.All(query, t => Assert.False(t.Value)); + return AssertQuery( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Select( + c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" })); } - [ConditionalFact] - public virtual void Select_bitwise_and_or() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_bitwise_and_or(bool async) { - using var context = CreateContext(); - var query = context.Customers.OrderBy(c => c.CustomerID) - .Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" | c.CustomerID == "ANTON" }) - .ToList(); - - Assert.All(query.Where(c => c.CustomerID != "ANTON"), t => Assert.False(t.Value)); + return AssertQuery( + async, + ss => ss.Set().OrderBy(c => c.CustomerID) + .Select( + c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" | c.CustomerID == "ANTON" })); } [ConditionalTheory] @@ -3843,27 +3843,24 @@ public virtual Task Where_bitwise_binary_or(bool async) entryCount: 1); } - [ConditionalFact] - public virtual void Select_bitwise_or_with_logical_or() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_bitwise_or_with_logical_or(bool async) { - using var context = CreateContext(); - var query = context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" || c.CustomerID == "ANTON" }) - .ToList(); - - Assert.All(query.Take(3), t => Assert.True(t.Value)); - Assert.All(query.Skip(3), t => Assert.False(t.Value)); + return AssertQuery( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Select( + c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" | c.CustomerID == "ANATR" || c.CustomerID == "ANTON" })); } - [ConditionalFact] - public virtual void Select_bitwise_and_with_logical_and() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_bitwise_and_with_logical_and(bool async) { - using var context = CreateContext(); - var query = context.Customers.OrderBy(c => c.CustomerID).Select( - c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" && c.CustomerID == "ANTON" }) - .ToList(); - - Assert.All(query, t => Assert.False(t.Value)); + return AssertQuery( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Select( + c => new { c.CustomerID, Value = c.CustomerID == "ALFKI" & c.CustomerID == "ANATR" && c.CustomerID == "ANTON" })); } [ConditionalTheory] @@ -4221,18 +4218,13 @@ public virtual Task Select_expression_references_are_updated_correctly_with_subq .Where(x => x < nextYear)); } - [ConditionalFact] - public virtual void DefaultIfEmpty_without_group_join() + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task DefaultIfEmpty_without_group_join(bool async) { - using var context = CreateContext(); - var query = context.Customers - .Where(c => c.City == "London") - .DefaultIfEmpty() - .Where(d => d != null) - .Select(d => d.CustomerID) - .ToList(); - - Assert.Equal(6, query.Count); + return AssertQuery( + async, + ss => ss.Set().Where(c => c.City == "London").DefaultIfEmpty().Where(d => d != null).Select(d => d.CustomerID)); } [ConditionalTheory] @@ -6375,5 +6367,92 @@ public virtual Task Skip_0_Take_0_works_when_constant(bool async) .Select(e => e.Orders.OrderBy(o => o.OrderID).Skip(0).Take(0).Any()), assertOrder: true); } + + [ConditionalFact] + public virtual async Task ToListAsync_can_be_canceled() + { + for (var i = 0; i < 10; i++) + { + // without fix, this usually throws within 2 or three iterations + + using var context = CreateContext(); + var tokenSource = new CancellationTokenSource(); + var query = context.Employees.AsNoTracking().ToListAsync(tokenSource.Token); + tokenSource.Cancel(); + List result = null; + Exception exception = null; + try + { + result = await query; + } + catch (Exception e) + { + exception = e; + } + + if (exception != null) + { + Assert.Null(result); + } + else + { + Assert.Equal(9, result.Count); + } + } + } + + [ConditionalFact(Skip = "Issue #17019")] + public virtual async Task Mixed_sync_async_query() + { + using var context = CreateContext(); + var results + = (await context.Customers + .Select( + c => new { c.CustomerID, Orders = context.Orders.Where(o => o.Customer.CustomerID == c.CustomerID) }) + .ToListAsync()) + .Select( + x => new + { + Orders = x.Orders + .GroupJoin( + new[] { "ALFKI" }, y => x.CustomerID, y => y, (h, id) => new { h.Customer }) + }) + .ToList(); + + Assert.Equal(830, results.SelectMany(r => r.Orders).ToList().Count); + } + + protected virtual async Task Single_Predicate_Cancellation_test(CancellationToken cancellationToken) + { + using var ctx = CreateContext(); + var result = await ctx.Customers.SingleAsync(c => c.CustomerID == "ALFKI", cancellationToken); + + Assert.Equal("ALFKI", result.CustomerID); + } + + [ConditionalFact] + public virtual async Task Mixed_sync_async_in_query_cache() + { + using var context = CreateContext(); + Assert.Equal(91, context.Customers.AsNoTracking().ToList().Count); + Assert.Equal(91, (await context.Customers.AsNoTracking().ToListAsync()).Count); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Load_should_track_results(bool async) + { + using var context = CreateContext(); + if (async) + { + await context.Customers.LoadAsync(); + } + else + { + context.Customers.Load(); + } + + Assert.Equal(91, context.ChangeTracker.Entries().Count()); + } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncFromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncFromSqlQuerySqlServerTest.cs deleted file mode 100644 index 2532a4d551e..00000000000 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncFromSqlQuerySqlServerTest.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.EntityFrameworkCore.TestUtilities; - -namespace Microsoft.EntityFrameworkCore.Query -{ - public class AsyncFromSqlQuerySqlServerTest : AsyncFromSqlQueryTestBase> - { - public AsyncFromSqlQuerySqlServerTest(NorthwindQuerySqlServerFixture fixture) - : base(fixture) - { - } - } -} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs index a903eb84a00..a758a8fe5f9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs @@ -3,6 +3,7 @@ using System.Data.Common; using System.Linq; +using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; @@ -18,33 +19,33 @@ public FromSqlQuerySqlServerTest(NorthwindQuerySqlServerFixture FromSqlRaw_queryable_composed(bool async) { - var queryString = base.FromSqlRaw_queryable_composed(); + var queryString = await base.FromSqlRaw_queryable_composed(async); var expected = @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -59,9 +60,9 @@ public override string FromSqlRaw_queryable_composed() return null; } - public override void FromSqlRaw_queryable_composed_after_removing_whitespaces() + public override async Task FromSqlRaw_queryable_composed_after_removing_whitespaces(bool async) { - base.FromSqlRaw_queryable_composed_after_removing_whitespaces(); + await base.FromSqlRaw_queryable_composed_after_removing_whitespaces(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -76,9 +77,9 @@ public override void FromSqlRaw_queryable_composed_after_removing_whitespaces() WHERE [c].[ContactName] LIKE N'%z%'"); } - public override void FromSqlRaw_queryable_composed_compiled() + public override async Task FromSqlRaw_queryable_composed_compiled(bool async) { - base.FromSqlRaw_queryable_composed_compiled(); + await base.FromSqlRaw_queryable_composed_compiled(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -88,9 +89,9 @@ public override void FromSqlRaw_queryable_composed_compiled() WHERE [c].[ContactName] LIKE N'%z%'"); } - public override void FromSqlRaw_queryable_composed_compiled_with_DbParameter() + public override async Task FromSqlRaw_queryable_composed_compiled_with_DbParameter(bool async) { - base.FromSqlRaw_queryable_composed_compiled_with_DbParameter(); + await base.FromSqlRaw_queryable_composed_compiled_with_DbParameter(async); AssertSql( @"customer='CONSH' (Nullable = false) (Size = 5) @@ -102,9 +103,9 @@ public override void FromSqlRaw_queryable_composed_compiled_with_DbParameter() WHERE [c].[ContactName] LIKE N'%z%'"); } - public override void FromSqlRaw_queryable_composed_compiled_with_nameless_DbParameter() + public override async Task FromSqlRaw_queryable_composed_compiled_with_nameless_DbParameter(bool async) { - base.FromSqlRaw_queryable_composed_compiled_with_nameless_DbParameter(); + await base.FromSqlRaw_queryable_composed_compiled_with_nameless_DbParameter(async); AssertSql( @"p0='CONSH' (Nullable = false) (Size = 5) @@ -116,9 +117,9 @@ public override void FromSqlRaw_queryable_composed_compiled_with_nameless_DbPara WHERE [c].[ContactName] LIKE N'%z%'"); } - public override void FromSqlRaw_queryable_composed_compiled_with_parameter() + public override async Task FromSqlRaw_queryable_composed_compiled_with_parameter(bool async) { - base.FromSqlRaw_queryable_composed_compiled_with_parameter(); + await base.FromSqlRaw_queryable_composed_compiled_with_parameter(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -128,9 +129,9 @@ public override void FromSqlRaw_queryable_composed_compiled_with_parameter() WHERE [c].[ContactName] LIKE N'%z%'"); } - public override void FromSqlRaw_composed_contains() + public override async Task FromSqlRaw_composed_contains(bool async) { - base.FromSqlRaw_composed_contains(); + await base.FromSqlRaw_composed_contains(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -143,9 +144,9 @@ SELECT 1 WHERE [o].[CustomerID] = [c].[CustomerID])"); } - public override void FromSqlRaw_composed_contains2() + public override async Task FromSqlRaw_composed_contains2(bool async) { - base.FromSqlRaw_composed_contains2(); + await base.FromSqlRaw_composed_contains2(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -158,9 +159,9 @@ SELECT 1 WHERE [o].[CustomerID] = [c].[CustomerID])"); } - public override void FromSqlRaw_queryable_multiple_composed() + public override async Task FromSqlRaw_queryable_multiple_composed(bool async) { - base.FromSqlRaw_queryable_multiple_composed(); + await base.FromSqlRaw_queryable_multiple_composed(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] @@ -173,9 +174,9 @@ CROSS JOIN ( WHERE [c].[CustomerID] = [o].[CustomerID]"); } - public override void FromSqlRaw_queryable_multiple_composed_with_closure_parameters() + public override async Task FromSqlRaw_queryable_multiple_composed_with_closure_parameters(bool async) { - base.FromSqlRaw_queryable_multiple_composed_with_closure_parameters(); + await base.FromSqlRaw_queryable_multiple_composed_with_closure_parameters(async); AssertSql( @"p0='1997-01-01T00:00:00.0000000' @@ -191,9 +192,9 @@ CROSS JOIN ( WHERE [c].[CustomerID] = [o].[CustomerID]"); } - public override void FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters() + public override async Task FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters(bool async) { - base.FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters(); + await base.FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters(async); AssertSql( @"p0='London' (Size = 4000) @@ -223,9 +224,9 @@ CROSS JOIN ( WHERE [c].[CustomerID] = [o].[CustomerID]"); } - public override void FromSqlRaw_queryable_multiple_line_query() + public override async Task FromSqlRaw_queryable_multiple_line_query(bool async) { - base.FromSqlRaw_queryable_multiple_line_query(); + await base.FromSqlRaw_queryable_multiple_line_query(async); AssertSql( @"SELECT * @@ -233,9 +234,9 @@ public override void FromSqlRaw_queryable_multiple_line_query() WHERE ""City"" = 'London'"); } - public override void FromSqlRaw_queryable_composed_multiple_line_query() + public override async Task FromSqlRaw_queryable_composed_multiple_line_query(bool async) { - base.FromSqlRaw_queryable_composed_multiple_line_query(); + await base.FromSqlRaw_queryable_composed_multiple_line_query(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -246,9 +247,9 @@ public override void FromSqlRaw_queryable_composed_multiple_line_query() WHERE [c].[City] = N'London'"); } - public override void FromSqlRaw_queryable_with_parameters() + public override async Task FromSqlRaw_queryable_with_parameters(bool async) { - base.FromSqlRaw_queryable_with_parameters(); + await base.FromSqlRaw_queryable_with_parameters(async); AssertSql( @"p0='London' (Size = 4000) @@ -257,9 +258,9 @@ public override void FromSqlRaw_queryable_with_parameters() SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @p1"); } - public override void FromSqlRaw_queryable_with_parameters_inline() + public override async Task FromSqlRaw_queryable_with_parameters_inline(bool async) { - base.FromSqlRaw_queryable_with_parameters_inline(); + await base.FromSqlRaw_queryable_with_parameters_inline(async); AssertSql( @"p0='London' (Size = 4000) @@ -268,9 +269,9 @@ public override void FromSqlRaw_queryable_with_parameters_inline() SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @p1"); } - public override void FromSqlInterpolated_queryable_with_parameters_interpolated() + public override async Task FromSqlInterpolated_queryable_with_parameters_interpolated(bool async) { - base.FromSqlInterpolated_queryable_with_parameters_interpolated(); + await base.FromSqlInterpolated_queryable_with_parameters_interpolated(async); AssertSql( @"p0='London' (Size = 4000) @@ -279,9 +280,9 @@ public override void FromSqlInterpolated_queryable_with_parameters_interpolated( SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @p1"); } - public override void FromSqlInterpolated_queryable_with_parameters_inline_interpolated() + public override async Task FromSqlInterpolated_queryable_with_parameters_inline_interpolated(bool async) { - base.FromSqlInterpolated_queryable_with_parameters_inline_interpolated(); + await base.FromSqlInterpolated_queryable_with_parameters_inline_interpolated(async); AssertSql( @"p0='London' (Size = 4000) @@ -290,9 +291,9 @@ public override void FromSqlInterpolated_queryable_with_parameters_inline_interp SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @p1"); } - public override void FromSqlInterpolated_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated() + public override async Task FromSqlInterpolated_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated(bool async) { - base.FromSqlInterpolated_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated(); + await base.FromSqlInterpolated_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated(async); AssertSql( @"p0='London' (Size = 4000) @@ -322,9 +323,9 @@ CROSS JOIN ( WHERE [c].[CustomerID] = [o].[CustomerID]"); } - public override void FromSqlRaw_queryable_with_null_parameter() + public override async Task FromSqlRaw_queryable_with_null_parameter(bool async) { - base.FromSqlRaw_queryable_with_null_parameter(); + await base.FromSqlRaw_queryable_with_null_parameter(async); AssertSql( @"p0=NULL (Nullable = false) @@ -332,9 +333,9 @@ public override void FromSqlRaw_queryable_with_null_parameter() SELECT * FROM ""Employees"" WHERE ""ReportsTo"" = @p0 OR (""ReportsTo"" IS NULL AND @p0 IS NULL)"); } - public override string FromSqlRaw_queryable_with_parameters_and_closure() + public override async Task FromSqlRaw_queryable_with_parameters_and_closure(bool async) { - var queryString = base.FromSqlRaw_queryable_with_parameters_and_closure(); + var queryString = await base.FromSqlRaw_queryable_with_parameters_and_closure(async); AssertSql( @"p0='London' (Size = 4000) @@ -359,9 +360,9 @@ public override string FromSqlRaw_queryable_with_parameters_and_closure() return null; } - public override void FromSqlRaw_queryable_simple_cache_key_includes_query_string() + public override async Task FromSqlRaw_queryable_simple_cache_key_includes_query_string(bool async) { - base.FromSqlRaw_queryable_simple_cache_key_includes_query_string(); + await base.FromSqlRaw_queryable_simple_cache_key_includes_query_string(async); AssertSql( @"SELECT * FROM ""Customers"" WHERE ""City"" = 'London'", @@ -369,9 +370,9 @@ public override void FromSqlRaw_queryable_simple_cache_key_includes_query_string @"SELECT * FROM ""Customers"" WHERE ""City"" = 'Seattle'"); } - public override void FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters() + public override async Task FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters(bool async) { - base.FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters(); + await base.FromSqlRaw_queryable_with_parameters_cache_key_includes_parameters(async); AssertSql( @"p0='London' (Size = 4000) @@ -385,17 +386,17 @@ public override void FromSqlRaw_queryable_with_parameters_cache_key_includes_par SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @p1"); } - public override void FromSqlRaw_queryable_simple_as_no_tracking_not_composed() + public override async Task FromSqlRaw_queryable_simple_as_no_tracking_not_composed(bool async) { - base.FromSqlRaw_queryable_simple_as_no_tracking_not_composed(); + await base.FromSqlRaw_queryable_simple_as_no_tracking_not_composed(async); AssertSql( @"SELECT * FROM ""Customers"""); } - public override void FromSqlRaw_queryable_simple_projection_composed() + public override async Task FromSqlRaw_queryable_simple_projection_composed(bool async) { - base.FromSqlRaw_queryable_simple_projection_composed(); + await base.FromSqlRaw_queryable_simple_projection_composed(async); AssertSql( @"SELECT [p].[ProductName] @@ -407,9 +408,9 @@ public override void FromSqlRaw_queryable_simple_projection_composed() ) AS [p]"); } - public override void FromSqlRaw_queryable_simple_include() + public override async Task FromSqlRaw_queryable_simple_include(bool async) { - base.FromSqlRaw_queryable_simple_include(); + await base.FromSqlRaw_queryable_simple_include(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] @@ -420,9 +421,9 @@ public override void FromSqlRaw_queryable_simple_include() ORDER BY [c].[CustomerID], [o].[OrderID]"); } - public override void FromSqlRaw_queryable_simple_composed_include() + public override async Task FromSqlRaw_queryable_simple_composed_include(bool async) { - base.FromSqlRaw_queryable_simple_composed_include(); + await base.FromSqlRaw_queryable_simple_composed_include(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] @@ -434,9 +435,9 @@ public override void FromSqlRaw_queryable_simple_composed_include() ORDER BY [c].[CustomerID], [o].[OrderID]"); } - public override void FromSqlRaw_annotations_do_not_affect_successive_calls() + public override async Task FromSqlRaw_annotations_do_not_affect_successive_calls(bool async) { - base.FromSqlRaw_annotations_do_not_affect_successive_calls(); + await base.FromSqlRaw_annotations_do_not_affect_successive_calls(async); AssertSql( @"SELECT * FROM ""Customers"" WHERE ""ContactName"" LIKE '%z%'", @@ -445,9 +446,9 @@ public override void FromSqlRaw_annotations_do_not_affect_successive_calls() FROM [Customers] AS [c]"); } - public override void FromSqlRaw_composed_with_nullable_predicate() + public override async Task FromSqlRaw_composed_with_nullable_predicate(bool async) { - base.FromSqlRaw_composed_with_nullable_predicate(); + await base.FromSqlRaw_composed_with_nullable_predicate(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -458,9 +459,9 @@ public override void FromSqlRaw_composed_with_nullable_predicate() ; } - public override void FromSqlRaw_with_dbParameter() + public override async Task FromSqlRaw_with_dbParameter(bool async) { - base.FromSqlRaw_with_dbParameter(); + await base.FromSqlRaw_with_dbParameter(async); AssertSql( @"@city='London' (Nullable = false) (Size = 6) @@ -468,18 +469,18 @@ public override void FromSqlRaw_with_dbParameter() SELECT * FROM ""Customers"" WHERE ""City"" = @city"); } - public override void FromSqlRaw_with_dbParameter_without_name_prefix() + public override async Task FromSqlRaw_with_dbParameter_without_name_prefix(bool async) { - base.FromSqlRaw_with_dbParameter_without_name_prefix(); + await base.FromSqlRaw_with_dbParameter_without_name_prefix(async); AssertSql( @"city='London' (Nullable = false) (Size = 6) SELECT * FROM ""Customers"" WHERE ""City"" = @city"); } - public override void FromSqlRaw_with_dbParameter_mixed() + public override async Task FromSqlRaw_with_dbParameter_mixed(bool async) { - base.FromSqlRaw_with_dbParameter_mixed(); + await base.FromSqlRaw_with_dbParameter_mixed(async); AssertSql( @"p0='London' (Size = 4000) @@ -493,9 +494,9 @@ public override void FromSqlRaw_with_dbParameter_mixed() SELECT * FROM ""Customers"" WHERE ""City"" = @city AND ""ContactTitle"" = @p1"); } - public override void FromSqlRaw_with_db_parameters_called_multiple_times() + public override async Task FromSqlRaw_with_db_parameters_called_multiple_times(bool async) { - base.FromSqlRaw_with_db_parameters_called_multiple_times(); + await base.FromSqlRaw_with_db_parameters_called_multiple_times(async); AssertSql( @"@id='ALFKI' (Nullable = false) (Size = 5) @@ -507,9 +508,9 @@ public override void FromSqlRaw_with_db_parameters_called_multiple_times() SELECT * FROM ""Customers"" WHERE ""CustomerID"" = @id"); } - public override void FromSqlRaw_with_SelectMany_and_include() + public override async Task FromSqlRaw_with_SelectMany_and_include(bool async) { - base.FromSqlRaw_with_SelectMany_and_include(); + await base.FromSqlRaw_with_SelectMany_and_include(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] @@ -523,9 +524,9 @@ CROSS JOIN ( ORDER BY [c].[CustomerID], [c0].[CustomerID], [o].[OrderID]"); } - public override void FromSqlRaw_with_join_and_include() + public override async Task FromSqlRaw_with_join_and_include(bool async) { - base.FromSqlRaw_with_join_and_include(); + await base.FromSqlRaw_with_join_and_include(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] @@ -539,9 +540,9 @@ INNER JOIN ( ORDER BY [c].[CustomerID], [o].[OrderID], [o0].[OrderID], [o0].[ProductID]"); } - public override void FromSqlInterpolated_with_inlined_db_parameter() + public override async Task FromSqlInterpolated_with_inlined_db_parameter(bool async) { - base.FromSqlInterpolated_with_inlined_db_parameter(); + await base.FromSqlInterpolated_with_inlined_db_parameter(async); AssertSql( @"@somename='ALFKI' (Nullable = false) (Size = 5) @@ -549,9 +550,9 @@ public override void FromSqlInterpolated_with_inlined_db_parameter() SELECT * FROM ""Customers"" WHERE ""CustomerID"" = @somename"); } - public override void FromSqlInterpolated_with_inlined_db_parameter_without_name_prefix() + public override async Task FromSqlInterpolated_with_inlined_db_parameter_without_name_prefix(bool async) { - base.FromSqlInterpolated_with_inlined_db_parameter_without_name_prefix(); + await base.FromSqlInterpolated_with_inlined_db_parameter_without_name_prefix(async); AssertSql( @"somename='ALFKI' (Nullable = false) (Size = 5) @@ -559,160 +560,9 @@ public override void FromSqlInterpolated_with_inlined_db_parameter_without_name_ SELECT * FROM ""Customers"" WHERE ""CustomerID"" = @somename"); } - [ConditionalFact] - public virtual void FromSqlRaw_in_subquery_with_dbParameter() + public override async Task FromSqlInterpolated_parameterization_issue_12213(bool async) { - using var context = CreateContext(); - var actual = context.Orders.Where( - o => - context.Customers - .FromSqlRaw( - @"SELECT * FROM ""Customers"" WHERE ""City"" = @city", - // ReSharper disable once FormatStringProblem - new SqlParameter("@city", "London")) - .Select(c => c.CustomerID) - .Contains(o.CustomerID)) - .ToArray(); - - Assert.Equal(46, actual.Length); - - AssertSql( - @"@city='London' (Nullable = false) (Size = 6) - -SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE EXISTS ( - SELECT 1 - FROM ( - SELECT * FROM ""Customers"" WHERE ""City"" = @city - ) AS [c] - WHERE [c].[CustomerID] = [o].[CustomerID])"); - } - - [ConditionalFact] - public virtual void FromSqlRaw_in_subquery_with_positional_dbParameter_without_name() - { - using var context = CreateContext(); - var actual = context.Orders.Where( - o => - context.Customers - .FromSqlRaw( - @"SELECT * FROM ""Customers"" WHERE ""City"" = {0}", - // ReSharper disable once FormatStringProblem - new SqlParameter { Value = "London" }) - .Select(c => c.CustomerID) - .Contains(o.CustomerID)) - .ToArray(); - - Assert.Equal(46, actual.Length); - - AssertSql( - @"p0='London' (Nullable = false) (Size = 6) - -SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE EXISTS ( - SELECT 1 - FROM ( - SELECT * FROM ""Customers"" WHERE ""City"" = @p0 - ) AS [c] - WHERE [c].[CustomerID] = [o].[CustomerID])"); - } - - [ConditionalFact] - public virtual void FromSqlRaw_in_subquery_with_positional_dbParameter_with_name() - { - using var context = CreateContext(); - var actual = context.Orders.Where( - o => - context.Customers - .FromSqlRaw( - @"SELECT * FROM ""Customers"" WHERE ""City"" = {0}", - // ReSharper disable once FormatStringProblem - new SqlParameter("@city", "London")) - .Select(c => c.CustomerID) - .Contains(o.CustomerID)) - .ToArray(); - - Assert.Equal(46, actual.Length); - - AssertSql( - @"@city='London' (Nullable = false) (Size = 6) - -SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE EXISTS ( - SELECT 1 - FROM ( - SELECT * FROM ""Customers"" WHERE ""City"" = @city - ) AS [c] - WHERE [c].[CustomerID] = [o].[CustomerID])"); - } - - [ConditionalFact] - public virtual void FromSqlRaw_with_dbParameter_mixed_in_subquery() - { - using var context = CreateContext(); - const string city = "London"; - const string title = "Sales Representative"; - - var actual = context.Orders.Where( - o => - context.Customers - .FromSqlRaw( - @"SELECT * FROM ""Customers"" WHERE ""City"" = {0} AND ""ContactTitle"" = @title", - city, - // ReSharper disable once FormatStringProblem - new SqlParameter("@title", title)) - .Select(c => c.CustomerID) - .Contains(o.CustomerID)) - .ToArray(); - - Assert.Equal(26, actual.Length); - - actual = context.Orders.Where( - o => - context.Customers - .FromSqlRaw( - @"SELECT * FROM ""Customers"" WHERE ""City"" = @city AND ""ContactTitle"" = {1}", - // ReSharper disable once FormatStringProblem - new SqlParameter("@city", city), - title) - .Select(c => c.CustomerID) - .Contains(o.CustomerID)) - .ToArray(); - - Assert.Equal(26, actual.Length); - - AssertSql( - @"p0='London' (Size = 4000) -@title='Sales Representative' (Nullable = false) (Size = 20) - -SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE EXISTS ( - SELECT 1 - FROM ( - SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @title - ) AS [c] - WHERE [c].[CustomerID] = [o].[CustomerID])", - // - @"@city='London' (Nullable = false) (Size = 6) -p1='Sales Representative' (Size = 4000) - -SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE EXISTS ( - SELECT 1 - FROM ( - SELECT * FROM ""Customers"" WHERE ""City"" = @city AND ""ContactTitle"" = @p1 - ) AS [c] - WHERE [c].[CustomerID] = [o].[CustomerID])"); - } - - public override void FromSqlInterpolated_parameterization_issue_12213() - { - base.FromSqlInterpolated_parameterization_issue_12213(); + await base.FromSqlInterpolated_parameterization_issue_12213(async); AssertSql( @"p0='10300' @@ -747,9 +597,9 @@ SELECT 1 WHERE [o0].[OrderID] = [o].[OrderID])"); } - public override void FromSqlRaw_does_not_parameterize_interpolated_string() + public override async Task FromSqlRaw_does_not_parameterize_interpolated_string(bool async) { - base.FromSqlRaw_does_not_parameterize_interpolated_string(); + await base.FromSqlRaw_does_not_parameterize_interpolated_string(async); AssertSql( @"p0='10250' @@ -757,9 +607,9 @@ public override void FromSqlRaw_does_not_parameterize_interpolated_string() SELECT * FROM ""Orders"" WHERE ""OrderID"" < @p0"); } - public override void Entity_equality_through_fromsql() + public override async Task Entity_equality_through_fromsql(bool async) { - base.Entity_equality_through_fromsql(); + await base.Entity_equality_through_fromsql(async); AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] @@ -770,9 +620,9 @@ public override void Entity_equality_through_fromsql() WHERE [c].[CustomerID] = N'VINET'"); } - public override void FromSqlRaw_with_set_operation() + public override async Task FromSqlRaw_with_set_operation(bool async) { - base.FromSqlRaw_with_set_operation(); + await base.FromSqlRaw_with_set_operation(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -786,9 +636,9 @@ UNION ALL ) AS [c0]"); } - public override void Line_endings_after_Select() + public override async Task Line_endings_after_Select(bool async) { - base.Line_endings_after_Select(); + await base.Line_endings_after_Select(async); AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -799,9 +649,9 @@ public override void Line_endings_after_Select() WHERE [c].[City] = N'Seattle'"); } - public override void FromSql_with_db_parameter_in_split_query() + public override async Task FromSql_with_db_parameter_in_split_query(bool async) { - base.FromSql_with_db_parameter_in_split_query(); + await base.FromSql_with_db_parameter_in_split_query(async); AssertSql( @"customerID='ALFKI' (Nullable = false) (Size = 5) @@ -832,6 +682,87 @@ public override void FromSql_with_db_parameter_in_split_query() ORDER BY [c].[CustomerID], [o].[OrderID]"); } + public override async Task FromSqlRaw_in_subquery_with_dbParameter(bool async) + { + await base.FromSqlRaw_in_subquery_with_dbParameter(async); + + AssertSql( + @"@city='London' (Nullable = false) (Size = 6) + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT * FROM ""Customers"" WHERE ""City"" = @city + ) AS [c] + WHERE [c].[CustomerID] = [o].[CustomerID])"); + } + + public override async Task FromSqlRaw_in_subquery_with_positional_dbParameter_without_name(bool async) + { + await base.FromSqlRaw_in_subquery_with_positional_dbParameter_without_name(async); + + AssertSql( + @"p0='London' (Nullable = false) (Size = 6) + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT * FROM ""Customers"" WHERE ""City"" = @p0 + ) AS [c] + WHERE [c].[CustomerID] = [o].[CustomerID])"); + } + + public override async Task FromSqlRaw_in_subquery_with_positional_dbParameter_with_name(bool async) + { + await base.FromSqlRaw_in_subquery_with_positional_dbParameter_with_name(async); + + AssertSql( + @"@city='London' (Nullable = false) (Size = 6) + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT * FROM ""Customers"" WHERE ""City"" = @city + ) AS [c] + WHERE [c].[CustomerID] = [o].[CustomerID])"); + } + + public override async Task FromSqlRaw_with_dbParameter_mixed_in_subquery(bool async) + { + await base.FromSqlRaw_with_dbParameter_mixed_in_subquery(async); + + AssertSql( + @"p0='London' (Size = 4000) +@title='Sales Representative' (Nullable = false) (Size = 20) + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @title + ) AS [c] + WHERE [c].[CustomerID] = [o].[CustomerID])", + // + @"@city='London' (Nullable = false) (Size = 6) +p1='Sales Representative' (Size = 4000) + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT * FROM ""Customers"" WHERE ""City"" = @city AND ""ContactTitle"" = @p1 + ) AS [c] + WHERE [c].[CustomerID] = [o].[CustomerID])"); + } + protected override DbParameter CreateDbParameter(string name, object value) => new SqlParameter { ParameterName = name, Value = value }; diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAsyncSimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAsyncSimpleQuerySqlServerTest.cs deleted file mode 100644 index 5e34a2486cb..00000000000 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAsyncSimpleQuerySqlServerTest.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.TestModels.Northwind; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; -using Xunit.Abstractions; - -// ReSharper disable AccessToDisposedClosure -// ReSharper disable InconsistentNaming -namespace Microsoft.EntityFrameworkCore.Query -{ - public class NorthwindAsyncSimpleQuerySqlServerTest : NorthwindAsyncSimpleQueryRelationalTestBase< - NorthwindQuerySqlServerFixture> - { - // ReSharper disable once UnusedParameter.Local - public NorthwindAsyncSimpleQuerySqlServerTest( - NorthwindQuerySqlServerFixture fixture, - ITestOutputHelper testOutputHelper) - : base(fixture) - { - Fixture.TestSqlLoggerFactory.Clear(); - //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); - } - - protected override bool CanExecuteQueryString - => true; - - [ConditionalFact] - public override Task Throws_on_concurrent_query_list() - { - return base.Throws_on_concurrent_query_list(); - } - - [ConditionalFact] - public Task Query_compiler_concurrency() - { - const int threadCount = 50; - - var tasks = new Task[threadCount]; - - for (var i = 0; i < threadCount; i++) - { - tasks[i] = Task.Run( - () => - { - using var context = CreateContext(); - using ((from c in context.Customers - where c.City == "London" - orderby c.CustomerID - select (from o1 in context.Orders - where o1.CustomerID == c.CustomerID - && o1.OrderDate.Value.Year == 1997 - orderby o1.OrderID - select (from o2 in context.Orders - where o1.CustomerID == c.CustomerID - orderby o2.OrderID - select o1.OrderID).ToList()).ToList()) - .GetEnumerator()) - { - } - }); - } - - return Task.WhenAll(tasks); - } - - [ConditionalFact(Skip = "Issue#16218")] - public Task Race_when_context_disposed_before_query_termination() - { - DbSet task; - - using (var context = CreateContext()) - { - task = context.Customers; - } - - return Assert.ThrowsAsync(() => task.SingleAsync(c => c.CustomerID == "ALFKI")); - } - - [ConditionalFact] - public Task Single_Predicate_Cancellation() - { - return Assert.ThrowsAnyAsync( - () => Single_Predicate_Cancellation_test(Fixture.TestSqlLoggerFactory.CancelQuery())); - } - - [ConditionalFact] - public async Task Concurrent_async_queries_are_serialized2() - { - using var context = CreateContext(); - await context.OrderDetails - .Where(od => od.OrderID > 0) - .Intersect( - context.OrderDetails - .Where(od => od.OrderID > 0)) - .Intersect( - context.OrderDetails - .Where(od => od.OrderID > 0)).ToListAsync(); - } - - [ConditionalFact] - public async Task Concurrent_async_queries_when_raw_query() - { - using var context = CreateContext(); - await using var asyncEnumerator = context.Customers.AsAsyncEnumerable().GetAsyncEnumerator(); - while (await asyncEnumerator.MoveNextAsync()) - { - // Outer query is buffered by default - await context.Database.ExecuteSqlRawAsync( - "[dbo].[CustOrderHist] @CustomerID = {0}", - asyncEnumerator.Current.CustomerID); - } - } - - [ConditionalFact(Skip = "Issue#16218")] - public override Task Select_bitwise_and_with_logical_and() - { - return base.Select_bitwise_and_with_logical_and(); - } - - [ConditionalFact(Skip = "Issue#16218")] - public override Task Mixed_sync_async_in_query_cache() - { - return base.Mixed_sync_async_in_query_cache(); - } - } -} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index bb8ab933587..21a87d0cd24 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -2783,9 +2783,9 @@ FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]"); } - public override void Select_bitwise_or() + public override async Task Select_bitwise_or(bool async) { - base.Select_bitwise_or(); + await base.Select_bitwise_or(async); AssertSql( @"SELECT [c].[CustomerID], CASE @@ -2799,9 +2799,9 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); } - public override void Select_bitwise_or_multiple() + public override async Task Select_bitwise_or_multiple(bool async) { - base.Select_bitwise_or_multiple(); + await base.Select_bitwise_or_multiple(async); AssertSql( @"SELECT [c].[CustomerID], (CASE @@ -2818,9 +2818,9 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); } - public override void Select_bitwise_and() + public override async Task Select_bitwise_and(bool async) { - base.Select_bitwise_and(); + await base.Select_bitwise_and(async); AssertSql( @"SELECT [c].[CustomerID], CASE @@ -2834,9 +2834,9 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); } - public override void Select_bitwise_and_or() + public override async Task Select_bitwise_and_or(bool async) { - base.Select_bitwise_and_or(); + await base.Select_bitwise_and_or(async); AssertSql( @"SELECT [c].[CustomerID], (CASE @@ -2949,9 +2949,9 @@ FROM [Orders] AS [o] WHERE ([o].[OrderID] | 10248) = 10248"); } - public override void Select_bitwise_or_with_logical_or() + public override async Task Select_bitwise_or_with_logical_or(bool async) { - base.Select_bitwise_or_with_logical_or(); + await base.Select_bitwise_or_with_logical_or(async); AssertSql( @"SELECT [c].[CustomerID], CASE @@ -2968,9 +2968,9 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); } - public override void Select_bitwise_and_with_logical_and() + public override async Task Select_bitwise_and_with_logical_and(bool async) { - base.Select_bitwise_and_with_logical_and(); + await base.Select_bitwise_and_with_logical_and(async); AssertSql( @"SELECT [c].[CustomerID], CASE @@ -3252,9 +3252,9 @@ FROM [Orders] AS [o] WHERE [o].[OrderDate] IS NOT NULL AND (DATEPART(year, [o].[OrderDate]) < @__nextYear_0)"); } - public override void DefaultIfEmpty_without_group_join() + public override async Task DefaultIfEmpty_without_group_join(bool async) { - base.DefaultIfEmpty_without_group_join(); + await base.DefaultIfEmpty_without_group_join(async); AssertSql( @"SELECT [t].[CustomerID] @@ -5345,6 +5345,88 @@ WHERE [c].[CustomerID] LIKE N'F%' ORDER BY [c].[CustomerID]"); } + [ConditionalFact] + public async Task Single_Predicate_Cancellation() + { + await Assert.ThrowsAnyAsync( + async () => + await Single_Predicate_Cancellation_test(Fixture.TestSqlLoggerFactory.CancelQuery())); + } + + [ConditionalFact] + public Task Query_compiler_concurrency() + { + const int threadCount = 50; + + var tasks = new Task[threadCount]; + + for (var i = 0; i < threadCount; i++) + { + tasks[i] = Task.Run( + () => + { + using var context = CreateContext(); + using ((from c in context.Customers + where c.City == "London" + orderby c.CustomerID + select (from o1 in context.Orders + where o1.CustomerID == c.CustomerID + && o1.OrderDate.Value.Year == 1997 + orderby o1.OrderID + select (from o2 in context.Orders + where o1.CustomerID == c.CustomerID + orderby o2.OrderID + select o1.OrderID).ToList()).ToList()) + .GetEnumerator()) + { + } + }); + } + + return Task.WhenAll(tasks); + } + + [ConditionalFact(Skip = "Issue#16218")] + public Task Race_when_context_disposed_before_query_termination() + { + DbSet task; + + using (var context = CreateContext()) + { + task = context.Customers; + } + + return Assert.ThrowsAsync(() => task.SingleAsync(c => c.CustomerID == "ALFKI")); + } + + [ConditionalFact] + public async Task Concurrent_async_queries_are_serialized2() + { + using var context = CreateContext(); + await context.OrderDetails + .Where(od => od.OrderID > 0) + .Intersect( + context.OrderDetails + .Where(od => od.OrderID > 0)) + .Intersect( + context.OrderDetails + .Where(od => od.OrderID > 0)).ToListAsync(); + } + + [ConditionalFact] + public async Task Concurrent_async_queries_when_raw_query() + { + using var context = CreateContext(); + await using var asyncEnumerator = context.Customers.AsAsyncEnumerable().GetAsyncEnumerator(); + while (await asyncEnumerator.MoveNextAsync()) + { + // Outer query is buffered by default + await context.Database.ExecuteSqlRawAsync( + "[dbo].[CustOrderHist] @CustomerID = {0}", + asyncEnumerator.Current.CustomerID); + } + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/AsyncFromSqlQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/AsyncFromSqlQuerySqliteTest.cs deleted file mode 100644 index dde3ffeea2c..00000000000 --- a/test/EFCore.Sqlite.FunctionalTests/Query/AsyncFromSqlQuerySqliteTest.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.EntityFrameworkCore.TestUtilities; - -namespace Microsoft.EntityFrameworkCore.Query -{ - public class AsyncFromSqlQuerySqliteTest : AsyncFromSqlQueryTestBase> - { - public AsyncFromSqlQuerySqliteTest(NorthwindQuerySqliteFixture fixture) - : base(fixture) - { - } - } -} diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs index 87fe6ab7a4f..d9517738d4e 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/FromSqlQuerySqliteTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Data.Common; +using System.Threading.Tasks; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; @@ -17,9 +18,9 @@ public FromSqlQuerySqliteTest(NorthwindQuerySqliteFixture f fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } - public override string FromSqlRaw_queryable_composed() + public override async Task FromSqlRaw_queryable_composed(bool async) { - var queryString = base.FromSqlRaw_queryable_composed(); + var queryString = await base.FromSqlRaw_queryable_composed(async); var expected = @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" @@ -30,12 +31,12 @@ public override string FromSqlRaw_queryable_composed() Assert.Equal(expected, queryString, ignoreLineEndingDifferences: true); - return null; + return queryString; } - public override string FromSqlRaw_queryable_with_parameters_and_closure() + public override async Task FromSqlRaw_queryable_with_parameters_and_closure(bool async) { - var queryString = base.FromSqlRaw_queryable_with_parameters_and_closure(); + var queryString = await base.FromSqlRaw_queryable_with_parameters_and_closure(async); Assert.Equal( @".param set p0 'London' @@ -47,27 +48,31 @@ .param set @__contactTitle_1 'Sales Representative' ) AS ""c"" WHERE ""c"".""ContactTitle"" = @__contactTitle_1", queryString, ignoreLineEndingDifferences: true); - return null; + return queryString; } - public override void Bad_data_error_handling_invalid_cast_key() + public override Task Bad_data_error_handling_invalid_cast_key(bool async) { // Not supported on SQLite + return Task.CompletedTask; } - public override void Bad_data_error_handling_invalid_cast() + public override Task Bad_data_error_handling_invalid_cast(bool async) { // Not supported on SQLite + return Task.CompletedTask; } - public override void Bad_data_error_handling_invalid_cast_projection() + public override Task Bad_data_error_handling_invalid_cast_projection(bool async) { // Not supported on SQLite + return Task.CompletedTask; } - public override void Bad_data_error_handling_invalid_cast_no_tracking() + public override Task Bad_data_error_handling_invalid_cast_no_tracking(bool async) { // Not supported on SQLite + return Task.CompletedTask; } protected override DbParameter CreateDbParameter(string name, object value) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAsyncSimpleQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAsyncSimpleQuerySqliteTest.cs deleted file mode 100644 index 360cc732b67..00000000000 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAsyncSimpleQuerySqliteTest.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; - -// ReSharper disable InconsistentNaming -#pragma warning disable 1998 -namespace Microsoft.EntityFrameworkCore.Query -{ - public class NorthwindAsyncSimpleQuerySqliteTest : NorthwindAsyncSimpleQueryRelationalTestBase< - NorthwindQuerySqliteFixture> - { - public NorthwindAsyncSimpleQuerySqliteTest(NorthwindQuerySqliteFixture fixture) - : base(fixture) - { - } - - [ConditionalFact] - public async Task Single_Predicate_Cancellation() - { - await Assert.ThrowsAnyAsync( - async () => - await Single_Predicate_Cancellation_test(Fixture.TestSqlLoggerFactory.CancelQuery())); - } - } -} diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindMiscellaneousQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindMiscellaneousQuerySqliteTest.cs index 3aa50e52851..29da8fc7242 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindMiscellaneousQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindMiscellaneousQuerySqliteTest.cs @@ -319,6 +319,14 @@ public override async Task Select_correlated_subquery_ordered(bool async) (await Assert.ThrowsAsync( () => base.Select_correlated_subquery_ordered(async))).Message); + [ConditionalFact] + public async Task Single_Predicate_Cancellation() + { + await Assert.ThrowsAnyAsync( + async () => + await Single_Predicate_Cancellation_test(Fixture.TestSqlLoggerFactory.CancelQuery())); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }