|
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities;
|
|
|
|
|
using EntityFrameworkCore.Jet.Infrastructure;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using Microsoft.EntityFrameworkCore.Query;
|
|
|
|
|
using Microsoft.EntityFrameworkCore.Query.Internal;
|
|
|
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|
|
|
|
using Microsoft.EntityFrameworkCore.TestUtilities;
|
|
|
|
|
using Xunit;
|
|
|
|
|
using Xunit.Abstractions;
|
|
|
|
|
|
|
|
|
|
namespace EntityFrameworkCore.Jet.FunctionalTests.Query;
|
|
|
|
|
|
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
|
|
|
|
|
|
public class PrecompiledSqlPregenerationQueryJetTest(
|
|
|
|
|
PrecompiledSqlPregenerationQueryJetTest.PrecompiledSqlPregenerationQueryJetFixture fixture,
|
|
|
|
|
ITestOutputHelper testOutputHelper)
|
|
|
|
|
: PrecompiledSqlPregenerationQueryRelationalTestBase(fixture, testOutputHelper),
|
|
|
|
|
IClassFixture<PrecompiledSqlPregenerationQueryJetTest.PrecompiledSqlPregenerationQueryJetFixture>
|
|
|
|
|
{
|
|
|
|
|
protected override bool AlwaysPrintGeneratedSources
|
|
|
|
|
=> false;
|
|
|
|
|
|
|
|
|
|
public override async Task No_parameters()
|
|
|
|
|
{
|
|
|
|
|
await base.No_parameters();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = 'foo'
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Non_nullable_value_type()
|
|
|
|
|
{
|
|
|
|
|
await base.Non_nullable_value_type();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@id='8'
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Id` = @id
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Nullable_value_type()
|
|
|
|
|
{
|
|
|
|
|
await base.Nullable_value_type();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@id='8' (Nullable = true)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Id` = @id
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Nullable_reference_type()
|
|
|
|
|
{
|
|
|
|
|
await base.Nullable_reference_type();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name='bar' (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Non_nullable_reference_type()
|
|
|
|
|
{
|
|
|
|
|
await base.Non_nullable_reference_type();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name='bar' (Nullable = false) (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Nullable_and_non_nullable_value_types()
|
|
|
|
|
{
|
|
|
|
|
await base.Nullable_and_non_nullable_value_types();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@id1='8' (Nullable = true)
|
|
|
|
|
@id2='9'
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Id` = @id1 OR `b`.`Id` = @id2
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Two_nullable_reference_types()
|
|
|
|
|
{
|
|
|
|
|
await base.Two_nullable_reference_types();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name1='foo' (Size = 255)
|
|
|
|
|
@name2='bar' (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name1 OR `b`.`Name` = @name2
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Two_non_nullable_reference_types()
|
|
|
|
|
{
|
|
|
|
|
await base.Two_non_nullable_reference_types();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name1='foo' (Nullable = false) (Size = 255)
|
|
|
|
|
@name2='bar' (Nullable = false) (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name1 OR `b`.`Name` = @name2
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Nullable_and_non_nullable_reference_types()
|
|
|
|
|
{
|
|
|
|
|
await base.Nullable_and_non_nullable_reference_types();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name1='foo' (Size = 255)
|
|
|
|
|
@name2='bar' (Nullable = false) (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name1 OR `b`.`Name` = @name2
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Too_many_nullable_parameters_prevent_pregeneration()
|
|
|
|
|
{
|
|
|
|
|
await base.Too_many_nullable_parameters_prevent_pregeneration();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name1='foo' (Size = 255)
|
|
|
|
|
@name2='bar' (Size = 255)
|
|
|
|
|
@name3='baz' (Size = 255)
|
|
|
|
|
@name4='baq' (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name1 OR `b`.`Name` = @name2 OR `b`.`Name` = @name3 OR `b`.`Name` = @name4
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Many_non_nullable_parameters_do_not_prevent_pregeneration()
|
|
|
|
|
{
|
|
|
|
|
await base.Many_non_nullable_parameters_do_not_prevent_pregeneration();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
@name1='foo' (Nullable = false) (Size = 255)
|
|
|
|
|
@name2='bar' (Nullable = false) (Size = 255)
|
|
|
|
|
@name3='baz' (Nullable = false) (Size = 255)
|
|
|
|
|
@name4='baq' (Nullable = false) (Size = 255)
|
|
|
|
|
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` = @name1 OR `b`.`Name` = @name2 OR `b`.`Name` = @name3 OR `b`.`Name` = @name4
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Tests for the different querying enumerables
|
|
|
|
|
|
|
|
|
|
public override async Task Include_single_query()
|
|
|
|
|
{
|
|
|
|
|
await base.Include_single_query();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`, `p`.`Id`, `p`.`BlogId`, `p`.`Title`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
LEFT JOIN `Post` AS `p` ON `b`.`Id` = `p`.`BlogId`
|
|
|
|
|
ORDER BY `b`.`Id`
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Include_split_query()
|
|
|
|
|
{
|
|
|
|
|
await base.Include_split_query();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
ORDER BY `b`.`Id`
|
|
|
|
|
""",
|
|
|
|
|
//
|
|
|
|
|
"""
|
|
|
|
|
SELECT `p`.`Id`, `p`.`BlogId`, `p`.`Title`, `b`.`Id`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
INNER JOIN `Post` AS `p` ON `b`.`Id` = `p`.`BlogId`
|
|
|
|
|
ORDER BY `b`.`Id`
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task Final_GroupBy()
|
|
|
|
|
{
|
|
|
|
|
await base.Final_GroupBy();
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
SELECT `b`.`Name`, `b`.`Id`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
ORDER BY `b`.`Name`
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Tests for the different querying enumerables
|
|
|
|
|
|
|
|
|
|
[ConditionalFact]
|
|
|
|
|
public virtual async Task Do_not_cache_is_respected()
|
|
|
|
|
{
|
|
|
|
|
// The "do not cache" flag in the 2nd part of the query pipeline is turned on in provider-specific situations, so we test it
|
|
|
|
|
// here in SQL Server; note that SQL Server compatibility mode is set low to trigger this.
|
|
|
|
|
await Test(
|
|
|
|
|
"""
|
|
|
|
|
string[] names = ["foo", "bar"];
|
|
|
|
|
var blogs = await context.Blogs.Where(b => names.Contains(b.Name)).ToListAsync();
|
|
|
|
|
""",
|
|
|
|
|
interceptorCodeAsserter: code => Assert.Contains(nameof(RelationalCommandCache), code));
|
|
|
|
|
|
|
|
|
|
AssertSql(
|
|
|
|
|
"""
|
|
|
|
|
SELECT `b`.`Id`, `b`.`Name`
|
|
|
|
|
FROM `Blogs` AS `b`
|
|
|
|
|
WHERE `b`.`Name` IN ('foo', 'bar')
|
|
|
|
|
""");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class PrecompiledSqlPregenerationQueryJetFixture : PrecompiledSqlPregenerationQueryRelationalFixture
|
|
|
|
|
{
|
|
|
|
|
protected override ITestStoreFactory TestStoreFactory
|
|
|
|
|
=> JetTestStoreFactory.Instance;
|
|
|
|
|
|
|
|
|
|
/*public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
|
|
|
|
|
{
|
|
|
|
|
builder = base.AddOptions(builder);
|
|
|
|
|
|
|
|
|
|
// TODO: Figure out if there's a nice way to continue using the retrying strategy
|
|
|
|
|
var jetOptionsBuilder = new JetDbContextOptionsBuilder(builder);
|
|
|
|
|
jetOptionsBuilder
|
|
|
|
|
.ExecutionStrategy(d => new NonRetryingExecutionStrategy(d));
|
|
|
|
|
return builder;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
public override PrecompiledQueryTestHelpers PrecompiledQueryTestHelpers => JetPrecompiledQueryTestHelpers.Instance;
|
|
|
|
|
}
|
|
|
|
|
}
|