diff --git a/src/EFCore.Jet/Extensions/JetModelExtensions.cs b/src/EFCore.Jet/Extensions/JetModelExtensions.cs
index 7e9d39b..5bf60d5 100644
--- a/src/EFCore.Jet/Extensions/JetModelExtensions.cs
+++ b/src/EFCore.Jet/Extensions/JetModelExtensions.cs
@@ -2,6 +2,7 @@
using EntityFrameworkCore.Jet.Metadata;
using EntityFrameworkCore.Jet.Metadata.Internal;
+using EntityFrameworkCore.Jet.Utilities;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata;
@@ -10,6 +11,8 @@ namespace Microsoft.EntityFrameworkCore
{
public static class JetModelExtensions
{
+ public const string DefaultSequenceNameSuffix = "Sequence";
+
///
/// Returns the default identity seed.
///
@@ -123,5 +126,95 @@ namespace Microsoft.EntityFrameworkCore
/// The for the default .
public static ConfigurationSource? GetJetValueGenerationStrategyConfigurationSource([NotNull] this IConventionModel model)
=> model.FindAnnotation(JetAnnotationNames.ValueGenerationStrategy)?.GetConfigurationSource();
+
+ ///
+ /// Returns the suffix to append to the name of automatically created sequences.
+ ///
+ /// The model.
+ /// The name to use for the default key value generation sequence.
+ public static string GetJetSequenceNameSuffix(this IReadOnlyModel model)
+ => (string?)model[JetAnnotationNames.SequenceNameSuffix]
+ ?? DefaultSequenceNameSuffix;
+
+ ///
+ /// Sets the suffix to append to the name of automatically created sequences.
+ ///
+ /// The model.
+ /// The value to set.
+ public static void SetJetSequenceNameSuffix(this IMutableModel model, string? name)
+ {
+ Check.NullButNotEmpty(name, nameof(name));
+
+ model.SetOrRemoveAnnotation(JetAnnotationNames.SequenceNameSuffix, name);
+ }
+
+ ///
+ /// Sets the suffix to append to the name of automatically created sequences.
+ ///
+ /// The model.
+ /// The value to set.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// The configured value.
+ public static string? SetJetSequenceNameSuffix(
+ this IConventionModel model,
+ string? name,
+ bool fromDataAnnotation = false)
+ => (string?)model.SetOrRemoveAnnotation(
+ JetAnnotationNames.SequenceNameSuffix,
+ Check.NullButNotEmpty(name, nameof(name)),
+ fromDataAnnotation)?.Value;
+
+ ///
+ /// Returns the for the default value generation sequence name suffix.
+ ///
+ /// The model.
+ /// The for the default key value generation sequence name.
+ public static ConfigurationSource? GetJetSequenceNameSuffixConfigurationSource(this IConventionModel model)
+ => model.FindAnnotation(JetAnnotationNames.SequenceNameSuffix)?.GetConfigurationSource();
+
+ ///
+ /// Returns the schema to use for the default value generation sequence.
+ ///
+ ///
+ /// The model.
+ /// The schema to use for the default key value generation sequence.
+ public static string? GetJetSequenceSchema(this IReadOnlyModel model)
+ => (string?)model[JetAnnotationNames.SequenceSchema];
+
+ ///
+ /// Sets the schema to use for the default key value generation sequence.
+ ///
+ /// The model.
+ /// The value to set.
+ public static void SetJetSequenceSchema(this IMutableModel model, string? value)
+ {
+ Check.NullButNotEmpty(value, nameof(value));
+
+ model.SetOrRemoveAnnotation(JetAnnotationNames.SequenceSchema, value);
+ }
+
+ ///
+ /// Sets the schema to use for the default key value generation sequence.
+ ///
+ /// The model.
+ /// The value to set.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// The configured value.
+ public static string? SetJetSequenceSchema(
+ this IConventionModel model,
+ string? value,
+ bool fromDataAnnotation = false)
+ => (string?)model.SetOrRemoveAnnotation(
+ JetAnnotationNames.SequenceSchema,
+ Check.NullButNotEmpty(value, nameof(value)),
+ fromDataAnnotation)?.Value;
+
+ ///
+ /// Returns the for the default key value generation sequence schema.
+ ///
+ /// The model.
+ /// The for the default key value generation sequence schema.
+ public static ConfigurationSource? GetJetSequenceSchemaConfigurationSource(this IConventionModel model)
+ => model.FindAnnotation(JetAnnotationNames.SequenceSchema)?.GetConfigurationSource();
}
}
\ No newline at end of file
diff --git a/src/EFCore.Jet/Extensions/JetPropertyExtensions.cs b/src/EFCore.Jet/Extensions/JetPropertyExtensions.cs
index 39978b1..3f17427 100644
--- a/src/EFCore.Jet/Extensions/JetPropertyExtensions.cs
+++ b/src/EFCore.Jet/Extensions/JetPropertyExtensions.cs
@@ -8,6 +8,7 @@ using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System.Linq;
+using EntityFrameworkCore.Jet.Utilities;
// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore
@@ -302,5 +303,177 @@ namespace Microsoft.EntityFrameworkCore
?? property.FindTypeMapping()?.Converter)
== null;
}
+
+ ///
+ /// Returns the name to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The name to use for the key value generation sequence.
+ public static string? GetJetSequenceName(this IReadOnlyProperty property)
+ => (string?)property[JetAnnotationNames.SequenceName];
+
+ ///
+ /// Returns the name to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The identifier of the store object.
+ /// The name to use for the key value generation sequence.
+ public static string? GetJetSequenceName(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
+ {
+ var annotation = property.FindAnnotation(JetAnnotationNames.SequenceName);
+ if (annotation != null)
+ {
+ return (string?)annotation.Value;
+ }
+
+ return property.FindSharedStoreObjectRootProperty(storeObject)?.GetJetSequenceName(storeObject);
+ }
+
+ ///
+ /// Sets the name to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The sequence name to use.
+ public static void SetJetSequenceName(this IMutableProperty property, string? name)
+ => property.SetOrRemoveAnnotation(
+ JetAnnotationNames.SequenceName,
+ Check.NullButNotEmpty(name, nameof(name)));
+
+ ///
+ /// Sets the name to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The sequence name to use.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// The configured value.
+ public static string? SetJetSequenceName(
+ this IConventionProperty property,
+ string? name,
+ bool fromDataAnnotation = false)
+ => (string?)property.SetOrRemoveAnnotation(
+ JetAnnotationNames.SequenceName,
+ Check.NullButNotEmpty(name, nameof(name)),
+ fromDataAnnotation)?.Value;
+
+ ///
+ /// Returns the for the key value generation sequence name.
+ ///
+ /// The property.
+ /// The for the key value generation sequence name.
+ public static ConfigurationSource? GetJetSequenceNameConfigurationSource(this IConventionProperty property)
+ => property.FindAnnotation(JetAnnotationNames.SequenceName)?.GetConfigurationSource();
+
+ ///
+ /// Returns the schema to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The schema to use for the key value generation sequence.
+ public static string? GetJetSequenceSchema(this IReadOnlyProperty property)
+ => (string?)property[JetAnnotationNames.SequenceSchema];
+
+ ///
+ /// Returns the schema to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The identifier of the store object.
+ /// The schema to use for the key value generation sequence.
+ public static string? GetJetSequenceSchema(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
+ {
+ var annotation = property.FindAnnotation(JetAnnotationNames.SequenceSchema);
+ if (annotation != null)
+ {
+ return (string?)annotation.Value;
+ }
+
+ return property.FindSharedStoreObjectRootProperty(storeObject)?.GetJetSequenceSchema(storeObject);
+ }
+
+ ///
+ /// Sets the schema to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The schema to use.
+ public static void SetJetSequenceSchema(this IMutableProperty property, string? schema)
+ => property.SetOrRemoveAnnotation(
+ JetAnnotationNames.SequenceSchema,
+ Check.NullButNotEmpty(schema, nameof(schema)));
+
+ ///
+ /// Sets the schema to use for the key value generation sequence.
+ ///
+ /// The property.
+ /// The schema to use.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// The configured value.
+ public static string? SetJetSequenceSchema(
+ this IConventionProperty property,
+ string? schema,
+ bool fromDataAnnotation = false)
+ => (string?)property.SetOrRemoveAnnotation(
+ JetAnnotationNames.SequenceSchema,
+ Check.NullButNotEmpty(schema, nameof(schema)),
+ fromDataAnnotation)?.Value;
+
+ ///
+ /// Returns the for the key value generation sequence schema.
+ ///
+ /// The property.
+ /// The for the key value generation sequence schema.
+ public static ConfigurationSource? GetGetSequenceSchemaConfigurationSource(this IConventionProperty property)
+ => property.FindAnnotation(JetAnnotationNames.SequenceSchema)?.GetConfigurationSource();
+
+ ///
+ /// Finds the in the model to use for the key value generation pattern.
+ ///
+ /// The property.
+ /// The sequence to use, or if no sequence exists in the model.
+ public static IReadOnlySequence? FindJetSequence(this IReadOnlyProperty property)
+ {
+ var model = property.DeclaringEntityType.Model;
+
+ var sequenceName = property.GetJetSequenceName()
+ ?? model.GetJetSequenceNameSuffix();
+
+ var sequenceSchema = property.GetJetSequenceSchema()
+ ?? model.GetJetSequenceSchema();
+
+ return model.FindSequence(sequenceName, sequenceSchema);
+ }
+
+ ///
+ /// Finds the in the model to use for the key value generation pattern.
+ ///
+ /// The property.
+ /// The identifier of the store object.
+ /// The sequence to use, or if no sequence exists in the model.
+ public static IReadOnlySequence? FindJetSequence(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
+ {
+ var model = property.DeclaringEntityType.Model;
+
+ var sequenceName = property.GetJetSequenceName(storeObject)
+ ?? model.GetJetSequenceNameSuffix();
+
+ var sequenceSchema = property.GetJetSequenceSchema(storeObject)
+ ?? model.GetJetSequenceSchema();
+
+ return model.FindSequence(sequenceName, sequenceSchema);
+ }
+
+ ///
+ /// Finds the in the model to use for the key value generation pattern.
+ ///
+ /// The property.
+ /// The sequence to use, or if no sequence exists in the model.
+ public static ISequence? FindJetSequence(this IProperty property)
+ => (ISequence?)((IReadOnlyProperty)property).FindJetSequence();
+
+ ///
+ /// Finds the in the model to use for the key value generation pattern.
+ ///
+ /// The property.
+ /// The identifier of the store object.
+ /// The sequence to use, or if no sequence exists in the model.
+ public static ISequence? FindJetSequence(this IProperty property, in StoreObjectIdentifier storeObject)
+ => (ISequence?)((IReadOnlyProperty)property).FindJetSequence(storeObject);
}
}
\ No newline at end of file
diff --git a/src/EFCore.Jet/Metadata/Conventions/JetValueGenerationStrategyConvention.cs b/src/EFCore.Jet/Metadata/Conventions/JetValueGenerationStrategyConvention.cs
index a66da93..fa72be8 100644
--- a/src/EFCore.Jet/Metadata/Conventions/JetValueGenerationStrategyConvention.cs
+++ b/src/EFCore.Jet/Metadata/Conventions/JetValueGenerationStrategyConvention.cs
@@ -1,6 +1,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Linq;
using EntityFrameworkCore.Jet.Metadata;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
@@ -24,8 +25,14 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
[NotNull] ProviderConventionSetBuilderDependencies dependencies,
[NotNull] RelationalConventionSetBuilderDependencies relationalDependencies)
{
+ Dependencies = dependencies;
+ RelationalDependencies = relationalDependencies;
}
+ protected virtual ProviderConventionSetBuilderDependencies Dependencies { get; }
+
+ protected virtual RelationalConventionSetBuilderDependencies RelationalDependencies { get; }
+
///
/// Called after a model is initialized.
///
@@ -48,26 +55,24 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
foreach (var property in entityType.GetDeclaredProperties())
{
JetValueGenerationStrategy? strategy = null;
- var table = entityType.GetTableName();
- if (table != null)
+ var declaringTable = property.GetMappedStoreObjects(StoreObjectType.Table).FirstOrDefault();
+ if (declaringTable.Name != null!)
{
- var storeObject = StoreObjectIdentifier.Table(table, entityType.GetSchema());
- strategy = property.GetValueGenerationStrategy(storeObject);
+ strategy = property.GetValueGenerationStrategy(declaringTable);
if (strategy == JetValueGenerationStrategy.None
- && !IsStrategyNoneNeeded(property, storeObject))
+ && !IsStrategyNoneNeeded(property, declaringTable))
{
strategy = null;
}
}
else
{
- var view = entityType.GetViewName();
- if (view != null)
+ var declaringView = property.GetMappedStoreObjects(StoreObjectType.View).FirstOrDefault();
+ if (declaringView.Name != null!)
{
- var storeObject = StoreObjectIdentifier.View(view, entityType.GetViewSchema());
- strategy = property.GetValueGenerationStrategy(storeObject);
+ strategy = property.GetValueGenerationStrategy(declaringView);
if (strategy == JetValueGenerationStrategy.None
- && !IsStrategyNoneNeeded(property, storeObject))
+ && !IsStrategyNoneNeeded(property, declaringView))
{
strategy = null;
}
@@ -75,9 +80,23 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
}
// Needed for the annotation to show up in the model snapshot
- if (strategy != null)
+ if (strategy != null
+ && declaringTable.Name != null)
{
property.Builder.HasValueGenerationStrategy(strategy);
+
+ if (strategy == JetValueGenerationStrategy.Sequence)
+ {
+ var sequence = modelBuilder.HasSequence(
+ property.GetJetSequenceName(declaringTable)
+ ?? entityType.GetRootType().ShortName() + modelBuilder.Metadata.GetJetSequenceNameSuffix(),
+ property.GetJetSequenceSchema(declaringTable)
+ ?? modelBuilder.Metadata.GetJetSequenceSchema()).Metadata;
+
+ property.Builder.HasDefaultValueSql(
+ RelationalDependencies.UpdateSqlGenerator.GenerateObtainNextSequenceValueOperation(
+ sequence.Name, sequence.Schema));
+ }
}
}
}
diff --git a/src/EFCore.Jet/Metadata/Internal/JetAnnotationNames.cs b/src/EFCore.Jet/Metadata/Internal/JetAnnotationNames.cs
index a5f97db..7567be6 100644
--- a/src/EFCore.Jet/Metadata/Internal/JetAnnotationNames.cs
+++ b/src/EFCore.Jet/Metadata/Internal/JetAnnotationNames.cs
@@ -57,5 +57,23 @@ namespace EntityFrameworkCore.Jet.Metadata.Internal
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public const string IdentityIncrement = Prefix + "IdentityIncrement";
+
+ public const string SequenceNameSuffix = Prefix + "SequenceNameSuffix";
+
+ ///
+ /// 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.
+ ///
+ public const string SequenceName = Prefix + "SequenceName";
+
+ ///
+ /// 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.
+ ///
+ public const string SequenceSchema = Prefix + "SequenceSchema";
}
}
\ No newline at end of file
diff --git a/src/EFCore.Jet/Metadata/JetValueGenerationStrategy.cs b/src/EFCore.Jet/Metadata/JetValueGenerationStrategy.cs
index 0b47612..7aa6355 100644
--- a/src/EFCore.Jet/Metadata/JetValueGenerationStrategy.cs
+++ b/src/EFCore.Jet/Metadata/JetValueGenerationStrategy.cs
@@ -5,6 +5,7 @@ namespace EntityFrameworkCore.Jet.Metadata
public enum JetValueGenerationStrategy
{
None,
- IdentityColumn
+ IdentityColumn,
+ Sequence
}
}