Fix the precompiled query tests

pull/257/head
Christopher Jolly 1 year ago
parent 74c7e3f527
commit 3bd4232a07

@ -7,6 +7,7 @@
<AssemblyName>EntityFrameworkCore.Jet</AssemblyName>
<Platforms>AnyCPU;x86;x64</Platforms>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);EF9100</NoWarn>
</PropertyGroup>
<ItemGroup>

@ -39,6 +39,10 @@ namespace Microsoft.EntityFrameworkCore
/// <returns> The identity seed. </returns>
public static int? GetJetIdentitySeed(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
{
if (property is RuntimeProperty)
{
throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData);
}
var @override = property.FindOverrides(storeObject)?.FindAnnotation(JetAnnotationNames.IdentitySeed);
if (@override != null)
{

@ -56,6 +56,7 @@ namespace Microsoft.Extensions.DependencyInjection
.TryAdd<ICompiledQueryCacheKeyGenerator, JetCompiledQueryCacheKeyGenerator>()
.TryAdd<IExecutionStrategyFactory, JetExecutionStrategyFactory>()
.TryAdd<ISingletonOptions, IJetOptions>(p => p.GetRequiredService<IJetOptions>())
.TryAdd<IQueryCompilationContextFactory, JetQueryCompilationContextFactory>()
.TryAdd<IMethodCallTranslatorProvider, JetMethodCallTranslatorProvider>()
.TryAdd<IMemberTranslatorProvider, JetMemberTranslatorProvider>()
.TryAdd<IQuerySqlGeneratorFactory, JetQuerySqlGeneratorFactory>()

@ -153,10 +153,6 @@ namespace Microsoft.EntityFrameworkCore
{
return null;
}
// TODO: Remove
Debug.WriteLine("DELAY: " + (int)baseDelay.GetValueOrDefault().TotalMilliseconds);
return baseDelay;
}
}

@ -77,10 +77,10 @@ namespace EntityFrameworkCore.Jet.Metadata.Internal
public override IEnumerable<IAnnotation> For(IColumn column, bool designTime)
{
//Need to do this in both design and runtime
/*if (!designTime)
if (!designTime)
{
yield break;
}*/
}
var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema);
var property = column.PropertyMappings

@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.Query;
namespace EntityFrameworkCore.Jet.Query.Internal;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public class JetQueryCompilationContext : RelationalQueryCompilationContext
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public JetQueryCompilationContext(
QueryCompilationContextDependencies dependencies,
RelationalQueryCompilationContextDependencies relationalDependencies,
bool async)
: this(
dependencies, relationalDependencies, async, precompiling: false,
nonNullableReferenceTypeParameters: null)
{
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public JetQueryCompilationContext(
QueryCompilationContextDependencies dependencies,
RelationalQueryCompilationContextDependencies relationalDependencies,
bool async,
bool precompiling,
IReadOnlySet<string>? nonNullableReferenceTypeParameters)
: base(dependencies, relationalDependencies, async, precompiling, nonNullableReferenceTypeParameters)
{
}
/// <summary>
/// Tracks whether translation is currently within the argument of an aggregate method (e.g. MAX, COUNT); SQL Server does not
/// allow subqueries and aggregates in that context.
/// </summary>
/// <remarks>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </remarks>
public virtual bool InAggregateFunction { get; set; }
/// <inheritdoc />
public override bool SupportsPrecompiledQuery => true;
}

@ -0,0 +1,64 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using EntityFrameworkCore.Jet.Storage.Internal;
using Microsoft.EntityFrameworkCore.Query;
namespace EntityFrameworkCore.Jet.Query.Internal;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public class JetQueryCompilationContextFactory : IQueryCompilationContextFactory
{
private readonly IJetRelationalConnection _jetConnection;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public JetQueryCompilationContextFactory(
QueryCompilationContextDependencies dependencies,
RelationalQueryCompilationContextDependencies relationalDependencies,
IJetRelationalConnection jetConnection)
{
Dependencies = dependencies;
RelationalDependencies = relationalDependencies;
_jetConnection = jetConnection;
}
/// <summary>
/// Dependencies for this service.
/// </summary>
protected virtual QueryCompilationContextDependencies Dependencies { get; }
/// <summary>
/// Relational provider-specific dependencies for this service.
/// </summary>
protected virtual RelationalQueryCompilationContextDependencies RelationalDependencies { get; }
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual QueryCompilationContext Create(bool async)
=> new JetQueryCompilationContext(
Dependencies, RelationalDependencies, async);
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual QueryCompilationContext CreatePrecompiled(bool async, IReadOnlySet<string> nonNullableReferenceTypeParameters)
=> new JetQueryCompilationContext(
Dependencies, RelationalDependencies, async, precompiling: true,
nonNullableReferenceTypeParameters);
}

@ -367,7 +367,7 @@ public class JetSqlTranslatingExpressionVisitor : RelationalSqlTranslatingExpres
}
}
private static string? ConstructLikePatternParameter(
public static string? ConstructLikePatternParameter(
QueryContext queryContext,
string baseParameterName,
StartsEndsWithContains methodType)
@ -390,7 +390,7 @@ public class JetSqlTranslatingExpressionVisitor : RelationalSqlTranslatingExpres
_ => throw new UnreachableException()
};
private enum StartsEndsWithContains
public enum StartsEndsWithContains
{
StartsWith,
EndsWith,

@ -227,106 +227,6 @@ WHERE `c`.`Id` = @__id_0
#endregion
#region 9214
[ConditionalFact]
public async Task Default_schema_applied_when_no_function_schema()
{
var contextFactory = await InitializeAsync<Context9214>(seed: c => c.SeedAsync());
using (var context = contextFactory.CreateContext())
{
var result = context.Widgets.Where(w => w.Val == 1).Select(w => Context9214.AddOne(w.Val)).Single();
Assert.Equal(2, result);
AssertSql(
"""
SELECT TOP(2) [foo].[AddOne]([w].[Val])
FROM [foo].[Widgets] AS [w]
WHERE [w].[Val] = 1
""");
}
using (var context = contextFactory.CreateContext())
{
ClearLog();
var result = context.Widgets.Where(w => w.Val == 1).Select(w => Context9214.AddTwo(w.Val)).Single();
Assert.Equal(3, result);
AssertSql(
"""
SELECT TOP(2) [dbo].[AddTwo]([w].[Val])
FROM [foo].[Widgets] AS [w]
WHERE [w].[Val] = 1
""");
}
}
protected class Context9214(DbContextOptions options) : DbContext(options)
{
public DbSet<Widget9214> Widgets { get; set; }
#pragma warning disable IDE0060 // Remove unused parameter
public static int AddOne(int num)
=> throw new Exception();
public static int AddTwo(int num)
=> throw new Exception();
public static int AddThree(int num)
=> throw new Exception();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("foo");
modelBuilder.Entity<Widget9214>().ToTable("Widgets", "foo");
modelBuilder.HasDbFunction(typeof(Context9214).GetMethod(nameof(AddOne)));
modelBuilder.HasDbFunction(typeof(Context9214).GetMethod(nameof(AddTwo))).HasSchema("dbo");
}
public async Task SeedAsync()
{
var w1 = new Widget9214 { Val = 1 };
var w2 = new Widget9214 { Val = 2 };
var w3 = new Widget9214 { Val = 3 };
Widgets.AddRange(w1, w2, w3);
await SaveChangesAsync();
await Database.ExecuteSqlRawAsync(
"""
CREATE FUNCTION foo.AddOne (@num int)
RETURNS int
AS
BEGIN
return @num + 1 ;
END
""");
await Database.ExecuteSqlRawAsync(
"""
CREATE FUNCTION dbo.AddTwo (@num int)
RETURNS int
AS
BEGIN
return @num + 2 ;
END
""");
}
public class Widget9214
{
public int Id { get; set; }
public int Val { get; set; }
}
}
#endregion
#region 12482
[ConditionalFact]

@ -61,22 +61,22 @@ WHERE JSON_VALUE([j].[JsonThing], '$.StringProperty') = N'foo'
await base.Materialize_non_public();
AssertSql(
"""
""""
@p0='10' (Nullable = true)
@p1='9' (Nullable = true)
@p2='8' (Nullable = true)
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [NonPublicEntities] ([PrivateAutoProperty], [PrivateProperty], [_privateField])
OUTPUT INSERTED.[Id]
INSERT INTO `NonPublicEntities` (`PrivateAutoProperty`, `PrivateProperty`, `_privateField`)
VALUES (@p0, @p1, @p2);
""",
//
"""
SELECT TOP(2) [n].[Id], [n].[PrivateAutoProperty], [n].[PrivateProperty], [n].[_privateField]
FROM [NonPublicEntities] AS [n]
""");
SELECT `Id`
FROM `NonPublicEntities`
WHERE @@ROWCOUNT = 1 AND `Id` = @@identity;
"""",
//
""""
SELECT TOP 2 `n`.`Id`, `n`.`PrivateAutoProperty`, `n`.`PrivateProperty`, `n`.`_privateField`
FROM `NonPublicEntities` AS `n`
"""");
}
[ConditionalFact]

@ -31,9 +31,9 @@ public class PrecompiledSqlPregenerationQueryJetTest(
AssertSql(
"""
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = N'foo'
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = 'foo'
""");
}
@ -45,9 +45,9 @@ WHERE [b].[Name] = N'foo'
"""
@__id_0='8'
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] = @__id_0
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Id` = @__id_0
""");
}
@ -59,9 +59,9 @@ WHERE [b].[Id] = @__id_0
"""
@__id_0='8' (Nullable = true)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] = @__id_0
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Id` = @__id_0
""");
}
@ -71,11 +71,11 @@ WHERE [b].[Id] = @__id_0
AssertSql(
"""
@__name_0='bar' (Size = 4000)
@__name_0='bar' (Size = 255)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name_0
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name_0
""");
}
@ -85,11 +85,11 @@ WHERE [b].[Name] = @__name_0
AssertSql(
"""
@__name_0='bar' (Nullable = false) (Size = 4000)
@__name_0='bar' (Nullable = false) (Size = 255)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name_0
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name_0
""");
}
@ -102,9 +102,9 @@ WHERE [b].[Name] = @__name_0
@__id1_0='8' (Nullable = true)
@__id2_1='9'
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] = @__id1_0 OR [b].[Id] = @__id2_1
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Id` = @__id1_0 OR `b`.`Id` = @__id2_1
""");
}
@ -114,12 +114,12 @@ WHERE [b].[Id] = @__id1_0 OR [b].[Id] = @__id2_1
AssertSql(
"""
@__name1_0='foo' (Size = 4000)
@__name2_1='bar' (Size = 4000)
@__name1_0='foo' (Size = 255)
@__name2_1='bar' (Size = 255)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name1_0 OR `b`.`Name` = @__name2_1
""");
}
@ -129,12 +129,12 @@ WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
AssertSql(
"""
@__name1_0='foo' (Nullable = false) (Size = 4000)
@__name2_1='bar' (Nullable = false) (Size = 4000)
@__name1_0='foo' (Nullable = false) (Size = 255)
@__name2_1='bar' (Nullable = false) (Size = 255)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name1_0 OR `b`.`Name` = @__name2_1
""");
}
@ -144,12 +144,12 @@ WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
AssertSql(
"""
@__name1_0='foo' (Size = 4000)
@__name2_1='bar' (Nullable = false) (Size = 4000)
@__name1_0='foo' (Size = 255)
@__name2_1='bar' (Nullable = false) (Size = 255)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name1_0 OR `b`.`Name` = @__name2_1
""");
}
@ -159,14 +159,14 @@ WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
AssertSql(
"""
@__name1_0='foo' (Size = 4000)
@__name2_1='bar' (Size = 4000)
@__name3_2='baz' (Size = 4000)
@__name4_3='baq' (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1 OR [b].[Name] = @__name3_2 OR [b].[Name] = @__name4_3
@__name1_0='foo' (Size = 255)
@__name2_1='bar' (Size = 255)
@__name3_2='baz' (Size = 255)
@__name4_3='baq' (Size = 255)
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name1_0 OR `b`.`Name` = @__name2_1 OR `b`.`Name` = @__name3_2 OR `b`.`Name` = @__name4_3
""");
}
@ -176,14 +176,14 @@ WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1 OR [b].[Name] = @__name
AssertSql(
"""
@__name1_0='foo' (Nullable = false) (Size = 4000)
@__name2_1='bar' (Nullable = false) (Size = 4000)
@__name3_2='baz' (Nullable = false) (Size = 4000)
@__name4_3='baq' (Nullable = false) (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1 OR [b].[Name] = @__name3_2 OR [b].[Name] = @__name4_3
@__name1_0='foo' (Nullable = false) (Size = 255)
@__name2_1='bar' (Nullable = false) (Size = 255)
@__name3_2='baz' (Nullable = false) (Size = 255)
@__name4_3='baq' (Nullable = false) (Size = 255)
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` = @__name1_0 OR `b`.`Name` = @__name2_1 OR `b`.`Name` = @__name3_2 OR `b`.`Name` = @__name4_3
""");
}
@ -195,10 +195,10 @@ WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1 OR [b].[Name] = @__name
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]
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`
""");
}
@ -208,16 +208,16 @@ ORDER BY [b].[Id]
AssertSql(
"""
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
ORDER BY [b].[Id]
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]
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`
""");
}
@ -227,9 +227,9 @@ ORDER BY [b].[Id]
AssertSql(
"""
SELECT [b].[Name], [b].[Id]
FROM [Blogs] AS [b]
ORDER BY [b].[Name]
SELECT `b`.`Name`, `b`.`Id`
FROM `Blogs` AS `b`
ORDER BY `b`.`Name`
""");
}
@ -249,9 +249,9 @@ var blogs = await context.Blogs.Where(b => names.Contains(b.Name)).ToListAsync()
AssertSql(
"""
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] IN (N'foo', N'bar')
SELECT `b`.`Id`, `b`.`Name`
FROM `Blogs` AS `b`
WHERE `b`.`Name` IN ('foo', 'bar')
""");
}
@ -260,7 +260,7 @@ WHERE [b].[Name] IN (N'foo', N'bar')
protected override ITestStoreFactory TestStoreFactory
=> JetTestStoreFactory.Instance;
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
/*public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
{
builder = base.AddOptions(builder);
@ -269,7 +269,7 @@ WHERE [b].[Name] IN (N'foo', N'bar')
jetOptionsBuilder
.ExecutionStrategy(d => new NonRetryingExecutionStrategy(d));
return builder;
}
}*/
public override PrecompiledQueryTestHelpers PrecompiledQueryTestHelpers => JetPrecompiledQueryTestHelpers.Instance;
}

@ -116,7 +116,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
}
public override DbContextOptionsBuilder AddProviderOptions(DbContextOptionsBuilder builder)
=> builder.UseJet(Connection, b => b.ApplyConfiguration().UseShortTextForSystemString()).EnableSensitiveDataLogging().EnableDetailedErrors();
=> builder.UseJet(Connection, b => b.ApplyConfiguration().UseShortTextForSystemString()).EnableSensitiveDataLogging();
private bool CreateDatabase(Func<DbContext, Task>? clean)
{

Loading…
Cancel
Save