Add further tests that were missing

pull/257/head
Christopher Jolly 1 year ago
parent 00c79ae541
commit fc09548111

@ -25,12 +25,10 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="increment"> The incremental value that is added to the identity value of the previous row that was loaded. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public static PropertyBuilder UseJetIdentityColumn(
[NotNull] this PropertyBuilder propertyBuilder,
this PropertyBuilder propertyBuilder,
int seed = 1,
int increment = 1)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
var property = propertyBuilder.Metadata;
property.SetValueGenerationStrategy(JetValueGenerationStrategy.IdentityColumn);
property.SetJetIdentitySeed(seed);
@ -39,6 +37,27 @@ namespace Microsoft.EntityFrameworkCore
return propertyBuilder;
}
/// <summary>
/// Configures the key column to use the Jet IDENTITY feature to generate values for new entities,
/// when targeting Jet. This method sets the property to be <see cref="ValueGenerated.OnAdd" />.
/// </summary>
/// <param name="columnBuilder">The builder for the column being configured.</param>
/// <param name="seed">The value that is used for the very first row loaded into the table.</param>
/// <param name="increment">The incremental value that is added to the identity value of the previous row that was loaded.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static ColumnBuilder UseJetIdentityColumn(
this ColumnBuilder columnBuilder,
int seed = 1,
int increment = 1)
{
var overrides = columnBuilder.Overrides;
overrides.SetValueGenerationStrategy(JetValueGenerationStrategy.IdentityColumn);
overrides.SetJetIdentitySeed(seed);
overrides.SetJetIdentityIncrement(increment);
return columnBuilder;
}
/// <summary>
/// Configures the key property to use the Jet IDENTITY feature to generate values for new entities,
/// when targeting Jet. This method sets the property to be <see cref="ValueGenerated.OnAdd" />.
@ -54,6 +73,21 @@ namespace Microsoft.EntityFrameworkCore
int increment = 1)
=> (PropertyBuilder<TProperty>)UseJetIdentityColumn((PropertyBuilder)propertyBuilder, seed, increment);
/// <summary>
/// Configures the key column to use the Jet IDENTITY feature to generate values for new entities,
/// when targeting Jet. This method sets the property to be <see cref="ValueGenerated.OnAdd" />.
/// </summary>
/// <typeparam name="TProperty">The type of the property being configured.</typeparam>
/// <param name="columnBuilder">The builder for the column being configured.</param>
/// <param name="seed">The value that is used for the very first row loaded into the table.</param>
/// <param name="increment">The incremental value that is added to the identity value of the previous row that was loaded.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static ColumnBuilder<TProperty> UseJetIdentityColumn<TProperty>(
this ColumnBuilder<TProperty> columnBuilder,
int seed = 1,
int increment = 1)
=> (ColumnBuilder<TProperty>)UseJetIdentityColumn((ColumnBuilder)columnBuilder, seed, increment);
/// <summary>
/// Configures the seed for Jet IDENTITY.
/// </summary>

@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using System.Linq;
using EntityFrameworkCore.Jet.Utilities;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Diagnostics;
// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore
@ -24,8 +25,16 @@ namespace Microsoft.EntityFrameworkCore
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> The identity seed. </returns>
public static int? GetJetIdentitySeed([NotNull] this IReadOnlyProperty property)
=> (int?)property[JetAnnotationNames.IdentitySeed];
public static int? GetJetIdentitySeed(this IReadOnlyProperty property)
{
if (property is RuntimeProperty)
{
throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData);
}
var annotation = property.FindAnnotation(JetAnnotationNames.IdentitySeed);
return (int?)annotation?.Value;
}
/// <summary>
/// Returns the identity seed.
@ -33,26 +42,47 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="property"> The property. </param>
/// <param name="storeObject"> The identifier of the store object. </param>
/// <returns> The identity seed. </returns>
public static int? GetJetIdentitySeed([NotNull] this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
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)
{
return (int?)@override.Value;
}
var annotation = property.FindAnnotation(JetAnnotationNames.IdentitySeed);
if (annotation != null)
if (annotation is not null)
{
return (int?)annotation.Value;
}
var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty(storeObject);
return sharedTableRootProperty != null
? sharedTableRootProperty.GetJetIdentitySeed(storeObject)
: null;
var sharedProperty = property.FindSharedStoreObjectRootProperty(storeObject);
return sharedProperty == null
? property.DeclaringType.Model.GetJetIdentitySeed()
: sharedProperty.GetJetIdentitySeed(storeObject);
}
/// <summary>
/// Returns the identity seed.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <returns>The identity seed.</returns>
public static int? GetJetIdentitySeed(this IReadOnlyRelationalPropertyOverrides overrides)
=> overrides is RuntimeRelationalPropertyOverrides
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
: (int?)overrides.FindAnnotation(JetAnnotationNames.IdentitySeed)?.Value;
/// <summary>
/// Sets the identity seed.
/// </summary>
/// <param name="property"> The property. </param>
/// <param name="seed"> The value to set. </param>
public static void SetJetIdentitySeed([NotNull] this IMutableProperty property, int? seed)
public static void SetJetIdentitySeed(this IMutableProperty property, int? seed)
=> property.SetOrRemoveAnnotation(
JetAnnotationNames.IdentitySeed,
seed);
@ -65,17 +95,63 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> The configured value. </returns>
public static int? SetJetIdentitySeed(
[NotNull] this IConventionProperty property,
this IConventionProperty property,
int? seed,
bool fromDataAnnotation = false)
{
property.SetOrRemoveAnnotation(
=> (int?)property.SetOrRemoveAnnotation(
JetAnnotationNames.IdentitySeed,
seed,
fromDataAnnotation);
fromDataAnnotation)?.Value;
return seed;
}
/// <summary>
/// Sets the identity seed for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="seed">The value to set.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
public static void SetJetIdentitySeed(
this IMutableProperty property,
int? seed,
in StoreObjectIdentifier storeObject)
=> property.GetOrCreateOverrides(storeObject)
.SetJetIdentitySeed(seed);
/// <summary>
/// Sets the identity seed for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="seed">The value to set.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static int? SetJetIdentitySeed(
this IConventionProperty property,
int? seed,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
=> property.GetOrCreateOverrides(storeObject, fromDataAnnotation)
.SetJetIdentitySeed(seed, fromDataAnnotation);
/// <summary>
/// Sets the identity seed for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <param name="seed">The value to set.</param>
public static void SetJetIdentitySeed(this IMutableRelationalPropertyOverrides overrides, int? seed)
=> overrides.SetOrRemoveAnnotation(JetAnnotationNames.IdentitySeed, seed);
/// <summary>
/// Sets the identity seed for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <param name="seed">The value to set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static int? SetJetIdentitySeed(
this IConventionRelationalPropertyOverrides overrides,
int? seed,
bool fromDataAnnotation = false)
=> (int?)overrides.SetOrRemoveAnnotation(JetAnnotationNames.IdentitySeed, seed, fromDataAnnotation)?.Value;
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the identity seed.
@ -85,13 +161,36 @@ namespace Microsoft.EntityFrameworkCore
public static ConfigurationSource? GetJetIdentitySeedConfigurationSource([NotNull] this IConventionProperty property)
=> property.FindAnnotation(JetAnnotationNames.IdentitySeed)?.GetConfigurationSource();
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the identity seed for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the identity seed.</returns>
public static ConfigurationSource? GetJetIdentitySeedConfigurationSource(
this IConventionProperty property,
in StoreObjectIdentifier storeObject)
=> property.FindOverrides(storeObject)?.GetJetIdentitySeedConfigurationSource();
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the identity seed for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the identity seed.</returns>
public static ConfigurationSource? GetJetIdentitySeedConfigurationSource(
this IConventionRelationalPropertyOverrides overrides)
=> overrides.FindAnnotation(JetAnnotationNames.IdentitySeed)?.GetConfigurationSource();
/// <summary>
/// Returns the identity increment.
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> The identity increment. </returns>
public static int? GetJetIdentityIncrement([NotNull] this IReadOnlyProperty property)
=> (int?)property[JetAnnotationNames.IdentityIncrement];
public static int? GetJetIdentityIncrement(this IReadOnlyProperty property)
=> (property is RuntimeProperty)
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
: (int?)property[JetAnnotationNames.IdentityIncrement]
?? property.DeclaringType.Model.GetJetIdentityIncrement();
/// <summary>
/// Returns the identity increment.
@ -99,26 +198,47 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="property"> The property. </param>
/// <param name="storeObject"> The identifier of the store object. </param>
/// <returns> The identity increment. </returns>
public static int? GetJetIdentityIncrement([NotNull] this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
public static int? GetJetIdentityIncrement(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
{
if (property is RuntimeProperty)
{
throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData);
}
var @override = property.FindOverrides(storeObject)?.FindAnnotation(JetAnnotationNames.IdentityIncrement);
if (@override != null)
{
return (int?)@override.Value;
}
var annotation = property.FindAnnotation(JetAnnotationNames.IdentityIncrement);
if (annotation != null)
{
return (int?)annotation.Value;
}
var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty(storeObject);
return sharedTableRootProperty != null
? sharedTableRootProperty.GetJetIdentityIncrement(storeObject)
: null;
var sharedProperty = property.FindSharedStoreObjectRootProperty(storeObject);
return sharedProperty == null
? property.DeclaringType.Model.GetJetIdentityIncrement()
: sharedProperty.GetJetIdentityIncrement(storeObject);
}
/// <summary>
/// Returns the identity increment.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <returns>The identity increment.</returns>
public static int? GetJetIdentityIncrement(this IReadOnlyRelationalPropertyOverrides overrides)
=> overrides is RuntimeRelationalPropertyOverrides
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
: (int?)overrides.FindAnnotation(JetAnnotationNames.IdentityIncrement)?.Value;
/// <summary>
/// Sets the identity increment.
/// </summary>
/// <param name="property"> The property. </param>
/// <param name="increment"> The value to set. </param>
public static void SetJetIdentityIncrement([NotNull] this IMutableProperty property, int? increment)
public static void SetJetIdentityIncrement(this IMutableProperty property, int? increment)
=> property.SetOrRemoveAnnotation(
JetAnnotationNames.IdentityIncrement,
increment);
@ -134,14 +254,61 @@ namespace Microsoft.EntityFrameworkCore
[NotNull] this IConventionProperty property,
int? increment,
bool fromDataAnnotation = false)
{
property.SetOrRemoveAnnotation(
=> (int?)property.SetOrRemoveAnnotation(
JetAnnotationNames.IdentityIncrement,
increment,
fromDataAnnotation);
fromDataAnnotation)?.Value;
return increment;
}
/// <summary>
/// Sets the identity increment for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="increment">The value to set.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
public static void SetJetIdentityIncrement(
this IMutableProperty property,
int? increment,
in StoreObjectIdentifier storeObject)
=> property.GetOrCreateOverrides(storeObject)
.SetJetIdentityIncrement(increment);
/// <summary>
/// Sets the identity increment for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="increment">The value to set.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static int? SetJetIdentityIncrement(
this IConventionProperty property,
int? increment,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
=> property.GetOrCreateOverrides(storeObject, fromDataAnnotation)
.SetJetIdentityIncrement(increment, fromDataAnnotation);
/// <summary>
/// Sets the identity increment for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <param name="increment">The value to set.</param>
public static void SetJetIdentityIncrement(this IMutableRelationalPropertyOverrides overrides, int? increment)
=> overrides.SetOrRemoveAnnotation(JetAnnotationNames.IdentityIncrement, increment);
/// <summary>
/// Sets the identity increment for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <param name="increment">The value to set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static int? SetJetIdentityIncrement(
this IConventionRelationalPropertyOverrides overrides,
int? increment,
bool fromDataAnnotation = false)
=> (int?)overrides.SetOrRemoveAnnotation(JetAnnotationNames.IdentityIncrement, increment, fromDataAnnotation)
?.Value;
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the identity increment.
@ -290,12 +457,8 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="property"> The property. </param>
/// <param name="value"> The strategy to use. </param>
public static void SetValueGenerationStrategy(
[NotNull] this IMutableProperty property, JetValueGenerationStrategy? value)
{
CheckValueGenerationStrategy(property, value);
property.SetOrRemoveAnnotation(JetAnnotationNames.ValueGenerationStrategy, value);
}
this IMutableProperty property, JetValueGenerationStrategy? value)
=> property.SetOrRemoveAnnotation(JetAnnotationNames.ValueGenerationStrategy, value);
/// <summary>
/// Sets the <see cref="JetValueGenerationStrategy" /> to use for the property.
@ -305,32 +468,64 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> The configured value. </returns>
public static JetValueGenerationStrategy? SetValueGenerationStrategy(
[NotNull] this IConventionProperty property,
this IConventionProperty property,
JetValueGenerationStrategy? value,
bool fromDataAnnotation = false)
{
CheckValueGenerationStrategy(property, value);
=> (JetValueGenerationStrategy?)property.SetOrRemoveAnnotation(
JetAnnotationNames.ValueGenerationStrategy, value, fromDataAnnotation)?.Value;
property.SetOrRemoveAnnotation(JetAnnotationNames.ValueGenerationStrategy, value, fromDataAnnotation);
/// <summary>
/// Sets the <see cref="JetValueGenerationStrategy" /> to use for the property for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The strategy to use.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
public static void SetValueGenerationStrategy(
this IMutableProperty property,
JetValueGenerationStrategy? value,
in StoreObjectIdentifier storeObject)
=> property.GetOrCreateOverrides(storeObject)
.SetValueGenerationStrategy(value);
return value;
}
/// <summary>
/// Sets the <see cref="JetValueGenerationStrategy" /> to use for the property for a particular table.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The strategy to use.</param>
/// <param name="storeObject">The identifier of the table containing the column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static JetValueGenerationStrategy? SetValueGenerationStrategy(
this IConventionProperty property,
JetValueGenerationStrategy? value,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
=> property.GetOrCreateOverrides(storeObject, fromDataAnnotation)
.SetValueGenerationStrategy(value, fromDataAnnotation);
private static void CheckValueGenerationStrategy(IReadOnlyProperty property, JetValueGenerationStrategy? value)
{
if (value != null)
{
var propertyType = property.ClrType;
/// <summary>
/// Sets the <see cref="JetValueGenerationStrategy" /> to use for the property for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <param name="value">The strategy to use.</param>
public static void SetValueGenerationStrategy(
this IMutableRelationalPropertyOverrides overrides,
JetValueGenerationStrategy? value)
=> overrides.SetOrRemoveAnnotation(JetAnnotationNames.ValueGenerationStrategy, value);
if (value == JetValueGenerationStrategy.IdentityColumn
&& !IsCompatibleWithValueGeneration(property))
{
throw new ArgumentException(
JetStrings.IdentityBadType(
property.Name, property.DeclaringType.DisplayName(), propertyType.ShortDisplayName()));
}
}
}
/// <summary>
/// Sets the <see cref="JetValueGenerationStrategy" /> to use for the property for a particular table.
/// </summary>
/// <param name="overrides">The property overrides.</param>
/// <param name="value">The strategy to use.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static JetValueGenerationStrategy? SetValueGenerationStrategy(
this IConventionRelationalPropertyOverrides overrides,
JetValueGenerationStrategy? value,
bool fromDataAnnotation = false)
=> (JetValueGenerationStrategy?)overrides.SetOrRemoveAnnotation(
JetAnnotationNames.ValueGenerationStrategy, value, fromDataAnnotation)?.Value;
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the <see cref="JetValueGenerationStrategy" />.

@ -12,8 +12,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.BulkUpdates;
public class NorthwindBulkUpdatesJetTest(
NorthwindBulkUpdatesJetFixture<NoopModelCustomizer> fixture,
ITestOutputHelper testOutputHelper)
: NorthwindBulkUpdatesRelationalTestBase<NorthwindBulkUpdatesJetFixture<NoopModelCustomizer>>(fixture, testOutputHelper)
ITestOutputHelper testOutputHelper) : NorthwindBulkUpdatesRelationalTestBase<NorthwindBulkUpdatesJetFixture<NoopModelCustomizer>>(fixture, testOutputHelper)
{
[ConditionalFact]
public virtual void Check_all_tests_overridden()

@ -5,6 +5,7 @@
<RootNamespace>EntityFrameworkCore.Jet.FunctionalTests</RootNamespace>
<AssemblyName>EntityFrameworkCore.Jet.FunctionalTests</AssemblyName>
<Platforms>AnyCPU;x86;x64</Platforms>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
<ItemGroup>
@ -71,7 +72,6 @@
<None Include="GraphUpdates\GraphUpdatesJetTest.cs" />
<None Include="GraphUpdates\ProxyGraphUpdatesJetTest.cs" />
<None Include="JetApiConsistencyTest.cs" />
<None Include="Migrations\MigrationsJetTest.cs" />
<None Remove="TestResults\**" />
</ItemGroup>
@ -104,7 +104,6 @@
<Compile Remove="GraphUpdates\GraphUpdatesJetTest.cs" />
<Compile Remove="GraphUpdates\ProxyGraphUpdatesJetTest.cs" />
<Compile Remove="JetApiConsistencyTest.cs" />
<Compile Remove="Migrations\MigrationsJetTest.cs" />
<Compile Remove="PropertyEntryJetTest.cs" />
</ItemGroup>

@ -19,7 +19,7 @@ using JetDatabaseCreator = EntityFrameworkCore.Jet.Storage.Internal.JetDatabaseC
// ReSharper disable InconsistentNaming
#nullable disable
namespace EntityFrameworkCore.Jet.FunctionalTests
namespace EntityFrameworkCore.Jet.FunctionalTests.Migrations
{
[JetCondition(JetCondition.IsNotCI)]
public class MigrationsInfrastructureJetTest(
@ -269,7 +269,7 @@ COMMIT TRANSACTION;
Assert.Equal("EntityFrameworkCore.Jet", ActiveProvider);
}
[ConditionalFact]
public async Task Empty_Migration_Creates_Database()
{

@ -0,0 +1,68 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// ReSharper disable InconsistentNaming
using EntityFrameworkCore.Jet.FunctionalTests.ModelBuilding;
using System;
namespace Microsoft.EntityFrameworkCore.ModelBuilding;
public class JetModelBuilderGenericTest : JetModelBuilderTestBase
{
public class JetGenericNonRelationship(JetModelBuilderFixture fixture) : JetNonRelationship(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericComplexType(JetModelBuilderFixture fixture) : JetComplexType(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericInheritance(JetModelBuilderFixture fixture) : JetInheritance(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericOneToMany(JetModelBuilderFixture fixture) : JetOneToMany(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericManyToOne(JetModelBuilderFixture fixture) : JetManyToOne(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericOneToOne(JetModelBuilderFixture fixture) : JetOneToOne(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericManyToMany(JetModelBuilderFixture fixture) : JetManyToMany(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
public class JetGenericOwnedTypes(JetModelBuilderFixture fixture) : JetOwnedTypes(fixture)
{
protected override TestModelBuilder CreateModelBuilder(
Action<ModelConfigurationBuilder>? configure)
=> new GenericTestModelBuilder(Fixture, configure);
}
}

@ -0,0 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// ReSharper disable InconsistentNaming
using System;
using Microsoft.EntityFrameworkCore;
namespace EntityFrameworkCore.Jet.FunctionalTests.ModelBuilding;
public class JetModelBuilderNonGenericTest : JetModelBuilderTestBase
{
public class JetNonGenericNonRelationship(JetModelBuilderFixture fixture) : JetNonRelationship(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericComplexType(JetModelBuilderFixture fixture) : JetComplexType(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericInheritance(JetModelBuilderFixture fixture) : JetInheritance(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericOneToMany(JetModelBuilderFixture fixture) : JetOneToMany(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericManyToOne(JetModelBuilderFixture fixture) : JetManyToOne(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericOneToOne(JetModelBuilderFixture fixture) : JetOneToOne(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericManyToMany(JetModelBuilderFixture fixture) : JetManyToMany(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
public class JetNonGenericOwnedTypes(JetModelBuilderFixture fixture) : JetOwnedTypes(fixture)
{
protected override TestModelBuilder CreateModelBuilder(Action<ModelConfigurationBuilder>? configure = null)
=> new NonGenericTestModelBuilder(Fixture, configure);
}
}

@ -0,0 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace EntityFrameworkCore.Jet.FunctionalTests.ModelBuilding;
public static class JetTestModelBuilderExtensions
{
}

@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.TestUtilities;
namespace EntityFrameworkCore.Jet.FunctionalTests.Query;
#nullable disable
public class OptionalDependentQueryJetFixture : OptionalDependentQueryFixtureBase
{
protected override ITestStoreFactory TestStoreFactory
=> JetTestStoreFactory.Instance;
}

@ -0,0 +1,140 @@
// 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 Microsoft.EntityFrameworkCore.Query;
using Xunit.Abstractions;
namespace EntityFrameworkCore.Jet.FunctionalTests.Query;
#nullable disable
public class OptionalDependentQueryJetTest : OptionalDependentQueryTestBase<OptionalDependentQueryJetFixture>
{
public OptionalDependentQueryJetTest(OptionalDependentQueryJetFixture fixture, ITestOutputHelper testOutputHelper)
: base(fixture)
{
Fixture.TestSqlLoggerFactory.Clear();
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
public override async Task Basic_projection_entity_with_all_optional(bool async)
{
await base.Basic_projection_entity_with_all_optional(async);
AssertSql(
"""
SELECT `e`.`Id`, `e`.`Name`, `e`.`Json`
FROM `EntitiesAllOptional` AS `e`
""");
}
public override async Task Basic_projection_entity_with_some_required(bool async)
{
await base.Basic_projection_entity_with_some_required(async);
AssertSql(
"""
SELECT `e`.`Id`, `e`.`Name`, `e`.`Json`
FROM `EntitiesSomeRequired` AS `e`
""");
}
public override async Task Filter_optional_dependent_with_all_optional_compared_to_null(bool async)
{
await base.Filter_optional_dependent_with_all_optional_compared_to_null(async);
AssertSql(
"""
SELECT `e`.`Id`, `e`.`Name`, `e`.`Json`
FROM `EntitiesAllOptional` AS `e`
WHERE (`e`.`Json`) IS NULL
""");
}
public override async Task Filter_optional_dependent_with_all_optional_compared_to_not_null(bool async)
{
await base.Filter_optional_dependent_with_all_optional_compared_to_not_null(async);
AssertSql(
"""
SELECT `e`.`Id`, `e`.`Name`, `e`.`Json`
FROM `EntitiesAllOptional` AS `e`
WHERE (`e`.`Json`) IS NOT NULL
""");
}
public override async Task Filter_optional_dependent_with_some_required_compared_to_null(bool async)
{
await base.Filter_optional_dependent_with_some_required_compared_to_null(async);
AssertSql(
"""
SELECT `e`.`Id`, `e`.`Name`, `e`.`Json`
FROM `EntitiesSomeRequired` AS `e`
WHERE (`e`.`Json`) IS NULL
""");
}
public override async Task Filter_optional_dependent_with_some_required_compared_to_not_null(bool async)
{
await base.Filter_optional_dependent_with_some_required_compared_to_not_null(async);
AssertSql(
"""
SELECT `e`.`Id`, `e`.`Name`, `e`.`Json`
FROM `EntitiesSomeRequired` AS `e`
WHERE (`e`.`Json`) IS NOT NULL
""");
}
public override async Task Filter_nested_optional_dependent_with_all_optional_compared_to_null(bool async)
{
await base.Filter_nested_optional_dependent_with_all_optional_compared_to_null(async);
AssertSql(
"""
SELECT [e].[Id], [e].[Name], [e].[Json]
FROM [EntitiesAllOptional] AS [e]
WHERE JSON_QUERY([e].[Json], '$.OpNav1') IS NULL
""");
}
public override async Task Filter_nested_optional_dependent_with_all_optional_compared_to_not_null(bool async)
{
await base.Filter_nested_optional_dependent_with_all_optional_compared_to_not_null(async);
AssertSql(
"""
SELECT [e].[Id], [e].[Name], [e].[Json]
FROM [EntitiesAllOptional] AS [e]
WHERE JSON_QUERY([e].[Json], '$.OpNav2') IS NOT NULL
""");
}
public override async Task Filter_nested_optional_dependent_with_some_required_compared_to_null(bool async)
{
await base.Filter_nested_optional_dependent_with_some_required_compared_to_null(async);
AssertSql(
"""
SELECT [e].[Id], [e].[Name], [e].[Json]
FROM [EntitiesSomeRequired] AS [e]
WHERE JSON_QUERY([e].[Json], '$.ReqNav1') IS NULL
""");
}
public override async Task Filter_nested_optional_dependent_with_some_required_compared_to_not_null(bool async)
{
await base.Filter_nested_optional_dependent_with_some_required_compared_to_not_null(async);
AssertSql(
"""
SELECT [e].[Id], [e].[Name], [e].[Json]
FROM [EntitiesSomeRequired] AS [e]
WHERE JSON_QUERY([e].[Json], '$.ReqNav2') IS NOT NULL
""");
}
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}

@ -0,0 +1,276 @@
// 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] = N'foo'
""");
}
public override async Task Non_nullable_value_type()
{
await base.Non_nullable_value_type();
AssertSql(
"""
@__id_0='8'
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] = @__id_0
""");
}
public override async Task Nullable_value_type()
{
await base.Nullable_value_type();
AssertSql(
"""
@__id_0='8' (Nullable = true)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] = @__id_0
""");
}
public override async Task Nullable_reference_type()
{
await base.Nullable_reference_type();
AssertSql(
"""
@__name_0='bar' (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name_0
""");
}
public override async Task Non_nullable_reference_type()
{
await base.Non_nullable_reference_type();
AssertSql(
"""
@__name_0='bar' (Nullable = false) (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name_0
""");
}
public override async Task Nullable_and_non_nullable_value_types()
{
await base.Nullable_and_non_nullable_value_types();
AssertSql(
"""
@__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
""");
}
public override async Task Two_nullable_reference_types()
{
await base.Two_nullable_reference_types();
AssertSql(
"""
@__name1_0='foo' (Size = 4000)
@__name2_1='bar' (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
""");
}
public override async Task Two_non_nullable_reference_types()
{
await base.Two_non_nullable_reference_types();
AssertSql(
"""
@__name1_0='foo' (Nullable = false) (Size = 4000)
@__name2_1='bar' (Nullable = false) (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
""");
}
public override async Task Nullable_and_non_nullable_reference_types()
{
await base.Nullable_and_non_nullable_reference_types();
AssertSql(
"""
@__name1_0='foo' (Size = 4000)
@__name2_1='bar' (Nullable = false) (Size = 4000)
SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Name] = @__name1_0 OR [b].[Name] = @__name2_1
""");
}
public override async Task Too_many_nullable_parameters_prevent_pregeneration()
{
await base.Too_many_nullable_parameters_prevent_pregeneration();
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
""");
}
public override async Task Many_non_nullable_parameters_do_not_prevent_pregeneration()
{
await base.Many_non_nullable_parameters_do_not_prevent_pregeneration();
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
""");
}
#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 (N'foo', N'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;
}
}
Loading…
Cancel
Save