Skip to content

Commit

Permalink
Add tests for split include and no tracking (#21218)
Browse files Browse the repository at this point in the history
Part of #20892
  • Loading branch information
smitpatel authored Jun 12, 2020
1 parent 71b78cc commit fc33923
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// 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.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.TestModels.Northwind;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Xunit;

// ReSharper disable FormatStringProblem
// ReSharper disable InconsistentNaming
// ReSharper disable ConvertToConstant.Local
// ReSharper disable AccessToDisposedClosure
namespace Microsoft.EntityFrameworkCore.Query
{
public abstract class NorthwindSplitIncludeNoTrackingQueryTestBase<TFixture> : NorthwindIncludeNoTrackingQueryTestBase<TFixture>
where TFixture : NorthwindQueryFixtureBase<NoopModelCustomizer>, new()
{
private static readonly MethodInfo _asSplitIncludeMethodInfo
= typeof(RelationalQueryableExtensions)
.GetTypeInfo().GetDeclaredMethod(nameof(RelationalQueryableExtensions.AsSplitQuery));

protected NorthwindSplitIncludeNoTrackingQueryTestBase(TFixture fixture)
: base(fixture)
{
}

public override async Task Include_closes_reader(bool async)
{
using var context = CreateContext();
if (async)
{
Assert.NotNull(await context.Set<Customer>().Include(c => c.Orders).AsNoTracking().AsSplitQuery().FirstOrDefaultAsync());
Assert.NotNull(await context.Set<Product>().AsNoTracking().ToListAsync());
}
else
{
Assert.NotNull(context.Set<Customer>().Include(c => c.Orders).AsNoTracking().AsSplitQuery().FirstOrDefault());
Assert.NotNull(context.Set<Product>().AsNoTracking().ToList());
}
}

public override async Task Include_collection_dependent_already_tracked(bool async)
{
using var context = CreateContext();
var orders = context.Set<Order>().Where(o => o.CustomerID == "ALFKI").ToList();
Assert.Equal(6, context.ChangeTracker.Entries().Count());
Assert.True(orders.All(o => o.Customer == null));

var customer
= async
? await context.Set<Customer>()
.Include(c => c.Orders)
.AsSplitQuery()
.AsNoTracking()
.SingleAsync(c => c.CustomerID == "ALFKI")
: context.Set<Customer>()
.Include(c => c.Orders)
.AsSplitQuery()
.AsNoTracking()
.Single(c => c.CustomerID == "ALFKI");

Assert.NotEqual(orders, customer.Orders, LegacyReferenceEqualityComparer.Instance);
Assert.Equal(6, customer.Orders.Count);
Assert.True(customer.Orders.All(e => ReferenceEquals(e.Customer, customer)));

Assert.Equal(6, context.ChangeTracker.Entries().Count());
Assert.True(orders.All(o => o.Customer == null));
}

public override async Task Include_collection_principal_already_tracked(bool async)
{
using var context = CreateContext();
var customer1 = context.Set<Customer>().Single(c => c.CustomerID == "ALFKI");
Assert.Single(context.ChangeTracker.Entries());

var customer2
= async
? await context.Set<Customer>()
.Include(c => c.Orders)
.AsSplitQuery()
.AsNoTracking()
.SingleAsync(c => c.CustomerID == "ALFKI")
: context.Set<Customer>()
.Include(c => c.Orders)
.AsSplitQuery()
.AsNoTracking()
.Single(c => c.CustomerID == "ALFKI");

Assert.NotSame(customer1, customer2);
Assert.Equal(6, customer2.Orders.Count);
Assert.True(customer2.Orders.All(o => o.Customer != null));
Assert.True(customer2.Orders.All(o => ReferenceEquals(o.Customer, customer2)));

Assert.Single(context.ChangeTracker.Entries());
}

public override async Task Include_reference_dependent_already_tracked(bool async)
{
using var context = CreateContext();
var customer = context.Set<Customer>().Single(o => o.CustomerID == "ALFKI");
Assert.Single(context.ChangeTracker.Entries());

var orders
= async
? await context.Set<Order>().Include(o => o.Customer).AsNoTracking().AsSplitQuery().Where(o => o.CustomerID == "ALFKI").ToListAsync()
: context.Set<Order>().Include(o => o.Customer).AsNoTracking().AsSplitQuery().Where(o => o.CustomerID == "ALFKI").ToList();

Assert.Equal(6, orders.Count);
Assert.True(orders.All(o => !ReferenceEquals(o.Customer, customer)));
Assert.True(orders.All(o => o.Customer != null));
Assert.Single(context.ChangeTracker.Entries());
}

public override async Task Include_collection_with_last_no_orderby(bool async)
{
Assert.Equal(
CoreStrings.TranslationFailed("DbSet<Customer>() .Reverse()"),
(await Assert.ThrowsAsync<InvalidOperationException>(
() => AssertLast(
async,
ss => ss.Set<Customer>().Include(c => c.Orders),
entryCount: 8))).Message.Replace("\r", "").Replace("\n", ""));
}

[ConditionalTheory(Skip = "Collection Include on nested collection")]
public override Task Multi_level_includes_are_applied_with_take(bool async)
{
return base.Multi_level_includes_are_applied_with_take(async);
}

[ConditionalTheory(Skip = "Collection Include on nested collection")]
public override Task Multi_level_includes_are_applied_with_skip(bool async)
{
return base.Multi_level_includes_are_applied_with_skip(async);
}

[ConditionalTheory(Skip = "Collection Include on nested collection")]
public override Task Multi_level_includes_are_applied_with_skip_take(bool async)
{
return base.Multi_level_includes_are_applied_with_skip_take(async);
}

protected override Expression RewriteServerQueryExpression(Expression serverQueryExpression)
{
serverQueryExpression = base.RewriteServerQueryExpression(serverQueryExpression);

return Expression.Call(
_asSplitIncludeMethodInfo.MakeGenericMethod(serverQueryExpression.Type.TryGetSequenceType()),
serverQueryExpression);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ public override async Task Include_closes_reader(bool async)
using var context = CreateContext();
if (async)
{
Assert.NotNull(await context.Set<Customer>().Include(c => c.Orders).AsNoTracking().AsSplitQuery().FirstOrDefaultAsync());
Assert.NotNull(await context.Set<Customer>().Include(c => c.Orders).AsSplitQuery().FirstOrDefaultAsync());
Assert.NotNull(await context.Set<Product>().AsNoTracking().ToListAsync());
}
else
{
Assert.NotNull(context.Set<Customer>().Include(c => c.Orders).AsNoTracking().AsSplitQuery().FirstOrDefault());
Assert.NotNull(context.Set<Customer>().Include(c => c.Orders).AsSplitQuery().FirstOrDefault());
Assert.NotNull(context.Set<Product>().AsNoTracking().ToList());
}
}
Expand Down Expand Up @@ -115,23 +115,23 @@ public override async Task Include_collection_with_last_no_orderby(bool async)
(await Assert.ThrowsAsync<InvalidOperationException>(
() => AssertLast(
async,
ss => ss.Set<Customer>().Include(c => c.Orders).AsSplitQuery(),
ss => ss.Set<Customer>().Include(c => c.Orders),
entryCount: 8))).Message.Replace("\r","").Replace("\n",""));
}

[ConditionalTheory(Skip = "Nested collection include")]
[ConditionalTheory(Skip = "Collection Include on nested collection")]
public override Task Multi_level_includes_are_applied_with_take(bool async)
{
return base.Multi_level_includes_are_applied_with_take(async);
}

[ConditionalTheory(Skip = "Nested collection include")]
[ConditionalTheory(Skip = "Collection Include on nested collection")]
public override Task Multi_level_includes_are_applied_with_skip(bool async)
{
return base.Multi_level_includes_are_applied_with_skip(async);
}

[ConditionalTheory(Skip = "Nested collection include")]
[ConditionalTheory(Skip = "Collection Include on nested collection")]
public override Task Multi_level_includes_are_applied_with_skip_take(bool async)
{
return base.Multi_level_includes_are_applied_with_skip_take(async);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ var customer2
Assert.NotSame(customer1, customer2);
Assert.Equal(6, customer2.Orders.Count);
Assert.True(customer2.Orders.All(o => o.Customer != null));
Assert.True(customer2.Orders.All(o => !ReferenceEquals(o.Customer, customer1)));
Assert.True(customer2.Orders.All(o => ReferenceEquals(o.Customer, customer2)));

Assert.Single(context.ChangeTracker.Entries());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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;
using Xunit.Abstractions;

namespace Microsoft.EntityFrameworkCore.Query
{
public class NorthwindSplitIncludeNoTrackingQuerySqlServerTest : NorthwindSplitIncludeNoTrackingQueryTestBase<NorthwindSplitIncludeNoTrackingQuerySqlServerTest.NorthwindQuerySqlServerMARSFixture>
{
// ReSharper disable once UnusedParameter.Local
public NorthwindSplitIncludeNoTrackingQuerySqlServerTest(NorthwindQuerySqlServerMARSFixture fixture, ITestOutputHelper testOutputHelper)
: base(fixture)
{
Fixture.TestSqlLoggerFactory.Clear();
//Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}

public class NorthwindQuerySqlServerMARSFixture : NorthwindQuerySqlServerFixture<NoopModelCustomizer>
{
protected override ITestStoreFactory TestStoreFactory => SqlServerNorthwindMARSTestStoreFactory.Instance;
}

private class SqlServerNorthwindMARSTestStoreFactory : SqlServerNorthwindTestStoreFactory
{
public static new SqlServerNorthwindMARSTestStoreFactory Instance { get; } = new SqlServerNorthwindMARSTestStoreFactory();

protected SqlServerNorthwindMARSTestStoreFactory()
{
}

public override TestStore GetOrCreate(string storeName)
=> SqlServerTestStore.GetOrCreate(Name, "Northwind.sql", multipleActiveResultSets: true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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.Threading.Tasks;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Xunit.Abstractions;

namespace Microsoft.EntityFrameworkCore.Query
{
public class NorthwindSplitIncludeNoTrackingQuerySqliteTest : NorthwindSplitIncludeNoTrackingQueryTestBase<NorthwindQuerySqliteFixture<NoopModelCustomizer>>
{
public NorthwindSplitIncludeNoTrackingQuerySqliteTest(NorthwindQuerySqliteFixture<NoopModelCustomizer> fixture, ITestOutputHelper testOutputHelper)
: base(fixture)
{
//TestSqlLoggerFactory.CaptureOutput(testOutputHelper);
}

// Sqlite does not support Apply operations
public override Task Include_collection_with_cross_apply_with_filter(bool async) => Task.CompletedTask;

public override Task Include_collection_with_outer_apply_with_filter(bool async) => Task.CompletedTask;
}
}

0 comments on commit fc33923

Please sign in to comment.