diff --git a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
index 3f80b2fa144..ecd60227ecb 100644
--- a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
+++ b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
@@ -62,6 +62,7 @@ public virtual void Generate(string builderName, IModel model, IndentedStringBui
CoreAnnotationNames.ChangeTrackingStrategy,
CoreAnnotationNames.OwnedTypes,
RelationalAnnotationNames.CheckConstraints,
+ RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.Views);
@@ -81,6 +82,11 @@ public virtual void Generate(string builderName, IModel model, IndentedStringBui
stringBuilder.AppendLine(";");
}
+ foreach (var sequence in model.GetSequences())
+ {
+ GenerateSequence(builderName, sequence, stringBuilder);
+ }
+
GenerateEntityTypes(builderName, Sort(model.GetEntityTypes().Where(et => !et.IsIgnoredByMigrations()).ToList()), stringBuilder);
}
@@ -338,6 +344,93 @@ protected virtual void GenerateBaseType(
}
}
+ ///
+ /// Generates code for an .
+ ///
+ /// The name of the builder variable.
+ /// The sequence.
+ /// The builder code is added to.
+ protected virtual void GenerateSequence(
+ [NotNull] string builderName,
+ [NotNull] ISequence sequence,
+ [NotNull] IndentedStringBuilder stringBuilder)
+ {
+ stringBuilder
+ .AppendLine()
+ .Append(builderName)
+ .Append(".HasSequence");
+
+ if (sequence.ClrType != Sequence.DefaultClrType)
+ {
+ stringBuilder
+ .Append("<")
+ .Append(Code.Reference(sequence.ClrType))
+ .Append(">");
+ }
+
+ stringBuilder
+ .Append("(")
+ .Append(Code.Literal(sequence.Name));
+
+ if (!string.IsNullOrEmpty(sequence.Schema)
+ && sequence.Model.GetDefaultSchema() != sequence.Schema)
+ {
+ stringBuilder
+ .Append(", ")
+ .Append(Code.Literal(sequence.Schema));
+ }
+
+ stringBuilder.Append(")");
+
+ using (stringBuilder.Indent())
+ {
+ if (sequence.StartValue != Sequence.DefaultStartValue)
+ {
+ stringBuilder
+ .AppendLine()
+ .Append(".StartsAt(")
+ .Append(Code.Literal(sequence.StartValue))
+ .Append(")");
+ }
+
+ if (sequence.IncrementBy != Sequence.DefaultIncrementBy)
+ {
+ stringBuilder
+ .AppendLine()
+ .Append(".IncrementsBy(")
+ .Append(Code.Literal(sequence.IncrementBy))
+ .Append(")");
+ }
+
+ if (sequence.MinValue != Sequence.DefaultMinValue)
+ {
+ stringBuilder
+ .AppendLine()
+ .Append(".HasMin(")
+ .Append(Code.Literal(sequence.MinValue))
+ .Append(")");
+ }
+
+ if (sequence.MaxValue != Sequence.DefaultMaxValue)
+ {
+ stringBuilder
+ .AppendLine()
+ .Append(".HasMax(")
+ .Append(Code.Literal(sequence.MaxValue))
+ .Append(")");
+ }
+
+ if (sequence.IsCyclic != Sequence.DefaultIsCyclic)
+ {
+ stringBuilder
+ .AppendLine()
+ .Append(".IsCyclic()");
+ }
+ }
+
+ stringBuilder.AppendLine(";");
+ }
+
///
/// Generates code for objects.
///
diff --git a/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs b/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs
index 7ba24ef6c2d..e525186dcdd 100644
--- a/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs
+++ b/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs
@@ -242,6 +242,7 @@ private IEnumerable GetAnnotationNamespaces(IEnumerable it
CoreAnnotationNames.DefiningQuery,
CoreAnnotationNames.QueryFilter,
RelationalAnnotationNames.CheckConstraints,
+ RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.TableColumnMappings,
@@ -252,7 +253,7 @@ private IEnumerable GetAnnotationNamespaces(IEnumerable it
var ignoredAnnotationTypes = new List
{
- RelationalAnnotationNames.DbFunction, RelationalAnnotationNames.SequencePrefix
+ RelationalAnnotationNames.DbFunction
};
return items.SelectMany(
diff --git a/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs b/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs
index 7be05d1a4e6..7aea5fd4d2e 100644
--- a/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs
+++ b/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs
@@ -11,7 +11,6 @@
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
-using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace Microsoft.EntityFrameworkCore.Migrations.Internal
@@ -61,6 +60,7 @@ public virtual IModel Process(IModel model)
if (version != null)
{
ProcessElement(model, version);
+ UpdateSequences(model, version);
foreach (var entityType in model.GetEntityTypes())
{
@@ -141,6 +141,34 @@ private void ProcessElement(IAnnotatable metadata, string version)
}
}
+ private void UpdateSequences(IModel model, string version)
+ {
+ if ((!version.StartsWith("1.", StringComparison.Ordinal)
+ && !version.StartsWith("2.", StringComparison.Ordinal)
+ && !version.StartsWith("3.", StringComparison.Ordinal))
+ || !(model is IMutableModel mutableModel))
+ {
+ return;
+ }
+
+ var sequences = model.GetAnnotations()
+#pragma warning disable CS0618 // Type or member is obsolete
+ .Where(a => a.Name.StartsWith(RelationalAnnotationNames.SequencePrefix, StringComparison.Ordinal))
+ .Select(a => new Sequence(model, a.Name));
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ var sequencesDictionary = new SortedDictionary<(string, string), Sequence>();
+ foreach (var sequence in sequences)
+ {
+ sequencesDictionary[(sequence.Name, sequence.Schema)] = sequence;
+ }
+
+ if (sequencesDictionary.Count > 0)
+ {
+ mutableModel[RelationalAnnotationNames.Sequences] = sequencesDictionary;
+ }
+ }
+
private void UpdateOwnedTypes(IMutableEntityType entityType)
{
var ownerships = entityType.GetDeclaredReferencingForeignKeys().Where(fk => fk.IsOwnership && fk.IsUnique)
diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
index 18421a9900e..3800b6f7477 100644
--- a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
+++ b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
@@ -263,15 +263,13 @@ protected virtual void GenerateOnModelCreating(
RemoveAnnotation(ref annotations, ChangeDetector.SkipDetectChangesAnnotation);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.MaxIdentifierLength);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.CheckConstraints);
+ RemoveAnnotation(ref annotations, RelationalAnnotationNames.Sequences);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Tables);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Views);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.DatabaseName);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.EntityTypeErrors);
var annotationsToRemove = new List();
- annotationsToRemove.AddRange(
- annotations.Where(
- a => a.Name.StartsWith(RelationalAnnotationNames.SequencePrefix, StringComparison.Ordinal)));
var lines = new List();
diff --git a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
index 60a7d2f4ef5..0ff936a6119 100644
--- a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
@@ -449,29 +449,28 @@ public static bool IsIgnoredByMigrations([NotNull] this IEntityType entityType)
return entityType.BaseType.IsIgnoredByMigrations();
}
- if (entityType.GetDefiningQuery() != null)
+ if (entityType.GetTableName() != null)
{
- return true;
+ return false;
}
if (entityType.FindAnnotation(RelationalAnnotationNames.QueryableFunctionResultType) != null)
return true;
var viewDefinition = entityType.FindAnnotation(RelationalAnnotationNames.ViewDefinition);
- if (viewDefinition == null)
+ if (viewDefinition?.Value != null)
{
- var ownership = entityType.FindOwnership();
- if (ownership != null
- && ownership.IsUnique
- && entityType.FindAnnotation(RelationalAnnotationNames.TableName) == null)
- {
- return ownership.PrincipalEntityType.IsIgnoredByMigrations();
- }
-
return false;
}
- return viewDefinition.Value == null;
+ var ownership = entityType.FindOwnership();
+ if (ownership != null
+ && ownership.IsUnique)
+ {
+ return ownership.PrincipalEntityType.IsIgnoredByMigrations();
+ }
+
+ return true;
}
}
}
diff --git a/src/EFCore.Relational/Extensions/RelationalModelExtensions.cs b/src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
index 4666e7bf083..c32f12aefb2 100644
--- a/src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
@@ -149,12 +149,8 @@ public static void SetMaxIdentifierLength([NotNull] this IConventionModel model,
/// the given schema was found.
///
public static ISequence FindSequence([NotNull] this IModel model, [NotNull] string name, [CanBeNull] string schema = null)
- {
- Check.NotEmpty(name, nameof(name));
- Check.NullButNotEmpty(schema, nameof(schema));
-
- return Sequence.FindSequence(model, name, schema);
- }
+ => Sequence.FindSequence(
+ Check.NotNull(model, nameof(model)), Check.NotEmpty(name, nameof(name)), Check.NullButNotEmpty(schema, nameof(schema)));
///
/// Finds an with the given name.
@@ -194,7 +190,7 @@ public static IConventionSequence FindSequence(
/// The sequence.
public static IMutableSequence AddSequence(
[NotNull] this IMutableModel model, [NotNull] string name, [CanBeNull] string schema = null)
- => new Sequence(model, name, schema, ConfigurationSource.Explicit);
+ => Sequence.AddSequence(model, name, schema, ConfigurationSource.Explicit);
///
/// Either returns the existing with the given name in the given schema
@@ -207,7 +203,7 @@ public static IMutableSequence AddSequence(
/// The sequence.
public static IConventionSequence AddSequence(
[NotNull] this IConventionModel model, [NotNull] string name, [CanBeNull] string schema = null, bool fromDataAnnotation = false)
- => new Sequence(
+ => Sequence.AddSequence(
(IMutableModel)model, name, schema,
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
@@ -223,7 +219,7 @@ public static IConventionSequence AddSequence(
///
public static IMutableSequence RemoveSequence(
[NotNull] this IMutableModel model, [NotNull] string name, [CanBeNull] string schema = null)
- => (IMutableSequence)Sequence.RemoveSequence(model, name, schema);
+ => Sequence.RemoveSequence(model, name, schema);
///
/// Removes the with the given name.
@@ -243,22 +239,22 @@ public static IConventionSequence RemoveSequence(
/// Returns all s contained in the model.
///
/// The model to get the sequences in.
- public static IReadOnlyList GetSequences([NotNull] this IModel model)
- => Sequence.GetSequences(model, RelationalAnnotationNames.SequencePrefix).ToList();
+ public static IEnumerable GetSequences([NotNull] this IModel model)
+ => Sequence.GetSequences(model);
///
/// Returns all s contained in the model.
///
/// The model to get the sequences in.
- public static IReadOnlyList GetSequences([NotNull] this IMutableModel model)
- => (IReadOnlyList)((IModel)model).GetSequences();
+ public static IEnumerable GetSequences([NotNull] this IMutableModel model)
+ => (IEnumerable)((IModel)model).GetSequences();
///
/// Returns all s contained in the model.
///
/// The model to get the sequences in.
- public static IReadOnlyList GetSequences([NotNull] this IConventionModel model)
- => (IReadOnlyList)((IModel)model).GetSequences();
+ public static IEnumerable GetSequences([NotNull] this IConventionModel model)
+ => (IEnumerable)((IModel)model).GetSequences();
///
/// Finds a that is mapped to the method represented by the given .
diff --git a/src/EFCore.Relational/Metadata/Internal/Sequence.cs b/src/EFCore.Relational/Metadata/Internal/Sequence.cs
index 948bc27f96a..f88dde18f3b 100644
--- a/src/EFCore.Relational/Metadata/Internal/Sequence.cs
+++ b/src/EFCore.Relational/Metadata/Internal/Sequence.cs
@@ -22,7 +22,23 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal
public class Sequence : IMutableSequence, IConventionSequence
{
private readonly IModel _model;
- private readonly string _annotationName;
+
+ private string _name { get; set; }
+ private string _schema { get; set; }
+ private long? _startValue { get; set; }
+ private int? _incrementBy { get; set; }
+ private long? _minValue { get; set; }
+ private long? _maxValue { get; set; }
+ private Type _clrType { get; set; }
+ private bool? _isCyclic { get; set; }
+
+ private ConfigurationSource _configurationSource;
+ private ConfigurationSource? _startValueConfigurationSource;
+ private ConfigurationSource? _incrementByConfigurationSource;
+ private ConfigurationSource? _minValueConfigurationSource;
+ private ConfigurationSource? _maxValueConfigurationSource;
+ private ConfigurationSource? _clrTypeConfigurationSource;
+ private ConfigurationSource? _isCyclicConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -88,28 +104,9 @@ public Sequence(
Check.NullButNotEmpty(schema, nameof(schema));
_model = model;
- _annotationName = BuildSequenceAnnotationName(RelationalAnnotationNames.SequencePrefix, name, schema);
-
- var data = new SequenceData
- {
- Name = name,
- Schema = schema,
- ClrType = DefaultClrType,
- IncrementBy = DefaultIncrementBy,
- StartValue = DefaultStartValue
- }.Serialize();
-
- if (configurationSource == ConfigurationSource.Explicit)
- {
- model.AddAnnotation(_annotationName, data);
- }
- else
- {
- ((IConventionModel)model).AddAnnotation(
- _annotationName,
- data,
- configurationSource == ConfigurationSource.DataAnnotation);
- }
+ _name = name;
+ _schema = schema;
+ _configurationSource = configurationSource;
}
///
@@ -118,13 +115,24 @@ public Sequence(
/// 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.
///
+ [Obsolete("Use the other constructor")]
public Sequence([NotNull] IModel model, [NotNull] string annotationName)
{
Check.NotNull(model, nameof(model));
Check.NotEmpty(annotationName, nameof(annotationName));
_model = model;
- _annotationName = annotationName;
+ _configurationSource = ConfigurationSource.Explicit;
+
+ var data = SequenceData.Deserialize((string)model[annotationName]);
+ _name = data.Name;
+ _schema = data.Schema;
+ _startValue = data.StartValue;
+ _incrementBy = data.IncrementBy;
+ _minValue = data.MinValue;
+ _maxValue = data.MaxValue;
+ _clrType = data.ClrType;
+ _isCyclic = data.IsCyclic;
}
///
@@ -133,14 +141,67 @@ public Sequence([NotNull] IModel model, [NotNull] string annotationName)
/// 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 static IEnumerable GetSequences([NotNull] IModel model, [NotNull] string annotationPrefix)
+ public static IEnumerable GetSequences([NotNull] IModel model)
+ => ((SortedDictionary<(string, string), Sequence>)model[RelationalAnnotationNames.Sequences])
+ ?.Values ?? Enumerable.Empty();
+
+ ///
+ /// 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 static Sequence FindSequence([NotNull] IModel model, [NotNull] string name, [CanBeNull] string schema)
{
- Check.NotNull(model, nameof(model));
- Check.NotEmpty(annotationPrefix, nameof(annotationPrefix));
+ var sequences = (SortedDictionary<(string, string), Sequence>)model[RelationalAnnotationNames.Sequences];
+ if (sequences == null
+ || !sequences.TryGetValue((name, schema), out var sequence))
+ {
+ return null;
+ }
+
+ return sequence;
+ }
- return model.GetAnnotations()
- .Where(a => a.Name.StartsWith(annotationPrefix, StringComparison.Ordinal))
- .Select(a => new Sequence(model, a.Name));
+ ///
+ /// 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 static Sequence AddSequence(
+ [NotNull] IMutableModel model, [NotNull] string name, [CanBeNull] string schema, ConfigurationSource configurationSource)
+ {
+ var sequence = new Sequence(model, name, schema, configurationSource);
+ var sequences = (SortedDictionary<(string, string), Sequence>)model[RelationalAnnotationNames.Sequences];
+ if (sequences == null)
+ {
+ sequences = new SortedDictionary<(string, string), Sequence>();
+ model[RelationalAnnotationNames.Sequences] = sequences;
+ }
+
+ sequences.Add((name, schema), sequence);
+ return sequence;
+ }
+
+ ///
+ /// 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 static IMutableSequence RemoveSequence([NotNull] IMutableModel model, [NotNull] string name, [CanBeNull] string schema)
+ {
+ var sequences = (SortedDictionary<(string, string), Sequence>)model[RelationalAnnotationNames.Sequences];
+ if (sequences == null
+ || !sequences.TryGetValue((name, schema), out var sequence))
+ {
+ return null;
+ }
+
+ sequences.Remove((name, schema));
+
+ return sequence;
}
///
@@ -165,7 +226,7 @@ public static IEnumerable GetSequences([NotNull] IModel model, [NotNul
/// 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 virtual string Name => GetData().Name;
+ public virtual string Name => _name;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -173,7 +234,7 @@ public static IEnumerable GetSequences([NotNull] IModel model, [NotNul
/// 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 virtual string Schema => GetData().Schema ?? Model.GetDefaultSchema();
+ public virtual string Schema => _schema ?? Model.GetDefaultSchema();
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -183,7 +244,7 @@ public static IEnumerable GetSequences([NotNull] IModel model, [NotNul
///
public virtual long StartValue
{
- get => GetData().StartValue;
+ get => _startValue ?? DefaultStartValue;
set => SetStartValue(value, ConfigurationSource.Explicit);
}
@@ -195,9 +256,11 @@ public virtual long StartValue
///
public virtual void SetStartValue(long? startValue, ConfigurationSource configurationSource)
{
- var data = GetData();
- data.StartValue = startValue ?? DefaultStartValue;
- SetData(data);
+ _startValue = startValue;
+
+ _startValueConfigurationSource = startValue == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_startValueConfigurationSource);
}
///
@@ -207,7 +270,7 @@ public virtual void SetStartValue(long? startValue, ConfigurationSource configur
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource? GetStartValueConfigurationSource()
- => ConfigurationSource.Explicit;
+ => _startValueConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -217,7 +280,7 @@ public virtual void SetStartValue(long? startValue, ConfigurationSource configur
///
public virtual int IncrementBy
{
- get => GetData().IncrementBy;
+ get => _incrementBy ?? DefaultIncrementBy;
set => SetIncrementBy(value, ConfigurationSource.Explicit);
}
@@ -229,9 +292,11 @@ public virtual int IncrementBy
///
public virtual void SetIncrementBy(int? incrementBy, ConfigurationSource configurationSource)
{
- var data = GetData();
- data.IncrementBy = incrementBy ?? DefaultIncrementBy;
- SetData(data);
+ _incrementBy = incrementBy;
+
+ _incrementByConfigurationSource = incrementBy == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_incrementByConfigurationSource);
}
///
@@ -241,7 +306,7 @@ public virtual void SetIncrementBy(int? incrementBy, ConfigurationSource configu
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource? GetIncrementByConfigurationSource()
- => ConfigurationSource.Explicit;
+ => _incrementByConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -251,7 +316,7 @@ public virtual void SetIncrementBy(int? incrementBy, ConfigurationSource configu
///
public virtual long? MinValue
{
- get => GetData().MinValue;
+ get => _minValue ?? DefaultMinValue;
set => SetMinValue(value, ConfigurationSource.Explicit);
}
@@ -263,9 +328,11 @@ public virtual long? MinValue
///
public virtual void SetMinValue(long? minValue, ConfigurationSource configurationSource)
{
- var data = GetData();
- data.MinValue = minValue ?? DefaultMinValue;
- SetData(data);
+ _minValue = minValue;
+
+ _minValueConfigurationSource = minValue == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_minValueConfigurationSource);
}
///
@@ -275,7 +342,7 @@ public virtual void SetMinValue(long? minValue, ConfigurationSource configuratio
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource? GetMinValueConfigurationSource()
- => ConfigurationSource.Explicit;
+ => _minValueConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -285,7 +352,7 @@ public virtual void SetMinValue(long? minValue, ConfigurationSource configuratio
///
public virtual long? MaxValue
{
- get => GetData().MaxValue;
+ get => _maxValue;
set => SetMaxValue(value, ConfigurationSource.Explicit);
}
@@ -297,9 +364,11 @@ public virtual long? MaxValue
///
public virtual void SetMaxValue(long? maxValue, ConfigurationSource configurationSource)
{
- var data = GetData();
- data.MaxValue = maxValue ?? DefaultMaxValue;
- SetData(data);
+ _maxValue = maxValue;
+
+ _maxValueConfigurationSource = maxValue == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_maxValueConfigurationSource);
}
///
@@ -309,7 +378,7 @@ public virtual void SetMaxValue(long? maxValue, ConfigurationSource configuratio
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource? GetMaxValueConfigurationSource()
- => ConfigurationSource.Explicit;
+ => _maxValueConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -328,7 +397,7 @@ public virtual void SetMaxValue(long? maxValue, ConfigurationSource configuratio
///
public virtual Type ClrType
{
- get => GetData().ClrType;
+ get => _clrType ?? DefaultClrType;
set => SetClrType(value, ConfigurationSource.Explicit);
}
@@ -340,15 +409,17 @@ public virtual Type ClrType
///
public virtual void SetClrType([CanBeNull] Type clrType, ConfigurationSource configurationSource)
{
- clrType ??= DefaultClrType;
- if (!SupportedTypes.Contains(clrType))
+ if (clrType != null
+ && !SupportedTypes.Contains(clrType))
{
throw new ArgumentException(RelationalStrings.BadSequenceType);
}
- var data = GetData();
- data.ClrType = clrType;
- SetData(data);
+ _clrType = clrType;
+
+ _clrTypeConfigurationSource = clrType == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_clrTypeConfigurationSource);
}
///
@@ -358,7 +429,7 @@ public virtual void SetClrType([CanBeNull] Type clrType, ConfigurationSource con
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource? GetClrTypeConfigurationSource()
- => ConfigurationSource.Explicit;
+ => _clrTypeConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -368,7 +439,7 @@ public virtual void SetClrType([CanBeNull] Type clrType, ConfigurationSource con
///
public virtual bool IsCyclic
{
- get => GetData().IsCyclic;
+ get => _isCyclic ?? DefaultIsCyclic;
set => SetIsCyclic(value, ConfigurationSource.Explicit);
}
@@ -380,9 +451,11 @@ public virtual bool IsCyclic
///
public virtual void SetIsCyclic(bool? cyclic, ConfigurationSource configurationSource)
{
- var data = GetData();
- data.IsCyclic = cyclic ?? DefaultIsCyclic;
- SetData(data);
+ _isCyclic = cyclic;
+
+ _isCyclicConfigurationSource = cyclic == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_isCyclicConfigurationSource);
}
///
@@ -392,7 +465,7 @@ public virtual void SetIsCyclic(bool? cyclic, ConfigurationSource configurationS
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource? GetIsCyclicConfigurationSource()
- => ConfigurationSource.Explicit;
+ => _isCyclicConfigurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -401,7 +474,7 @@ public virtual void SetIsCyclic(bool? cyclic, ConfigurationSource configurationS
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual ConfigurationSource GetConfigurationSource()
- => ((IConventionModel)Model).FindAnnotation(_annotationName).GetConfigurationSource();
+ => _configurationSource;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -410,14 +483,7 @@ public virtual ConfigurationSource GetConfigurationSource()
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual void UpdateConfigurationSource(ConfigurationSource configurationSource)
- => ((Model)Model).FindAnnotation(_annotationName).UpdateConfigurationSource(configurationSource);
-
- private SequenceData GetData() => SequenceData.Deserialize((string)Model[_annotationName]);
-
- private void SetData(SequenceData data)
- {
- Model[_annotationName] = data.Serialize();
- }
+ => _configurationSource = _configurationSource.Max(configurationSource);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -427,37 +493,6 @@ private void SetData(SequenceData data)
///
IConventionModel IConventionSequence.Model => (IConventionModel)Model;
- ///
- /// 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 static ISequence FindSequence([NotNull] IModel model, [NotNull] string name, [CanBeNull] string schema)
- {
- var annotationName = BuildSequenceAnnotationName(RelationalAnnotationNames.SequencePrefix, name, schema);
-
- return model[annotationName] == null ? null : new Sequence(model, annotationName);
- }
-
- ///
- /// 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 static ISequence RemoveSequence([NotNull] IMutableModel model, [NotNull] string name, [CanBeNull] string schema = null)
- {
- Check.NotEmpty(name, nameof(name));
- Check.NullButNotEmpty(schema, nameof(schema));
-
- var annotationName = BuildSequenceAnnotationName(RelationalAnnotationNames.SequencePrefix, name, schema);
- return model.RemoveAnnotation(annotationName) == null ? null : new Sequence(model, annotationName);
- }
-
- private static string BuildSequenceAnnotationName(string annotationPrefix, string name, string schema)
- => annotationPrefix + schema + "." + name;
-
///
/// 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
@@ -520,6 +555,7 @@ void IConventionSequence.SetClrType(Type clrType, bool fromDataAnnotation)
void IConventionSequence.SetIsCyclic(bool? cyclic, bool fromDataAnnotation)
=> SetIsCyclic(cyclic, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ [Obsolete("Don't use this in any new code")]
private sealed class SequenceData
{
public string Name { get; set; }
@@ -538,29 +574,6 @@ private sealed class SequenceData
public bool IsCyclic { get; set; }
- public string Serialize()
- {
- var builder = new StringBuilder();
-
- EscapeAndQuote(builder, Name);
- builder.Append(", ");
- EscapeAndQuote(builder, Schema);
- builder.Append(", ");
- EscapeAndQuote(builder, StartValue);
- builder.Append(", ");
- EscapeAndQuote(builder, IncrementBy);
- builder.Append(", ");
- EscapeAndQuote(builder, MinValue);
- builder.Append(", ");
- EscapeAndQuote(builder, MaxValue);
- builder.Append(", ");
- EscapeAndQuote(builder, ClrType.Name);
- builder.Append(", ");
- EscapeAndQuote(builder, IsCyclic);
-
- return builder.ToString();
- }
-
public static SequenceData Deserialize([NotNull] string value)
{
Check.NotEmpty(value, nameof(value));
diff --git a/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs b/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs
index d0da9d806a3..0dd7869292a 100644
--- a/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs
+++ b/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs
@@ -1,6 +1,8 @@
// 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;
+
namespace Microsoft.EntityFrameworkCore.Metadata
{
///
@@ -82,8 +84,14 @@ public static class RelationalAnnotationNames
///
/// The prefix for serialized sequence annotations.
///
+ [Obsolete("All sequences are stored in a single annotation now")]
public const string SequencePrefix = Prefix + "Sequence:";
+ ///
+ /// The name for sequence annotation.
+ ///
+ public const string Sequences = Prefix + "Sequences";
+
///
/// The name for check constraint annotations.
///
@@ -95,7 +103,7 @@ public static class RelationalAnnotationNames
public const string Filter = Prefix + "Filter";
///
- /// The name for DbFunction annotations.
+ /// The name for DbFunction annotation.
///
public const string DbFunction = Prefix + "DbFunction";
diff --git a/src/EFCore/Metadata/Internal/Property.cs b/src/EFCore/Metadata/Internal/Property.cs
index e6bb2d46d32..3013df6e679 100644
--- a/src/EFCore/Metadata/Internal/Property.cs
+++ b/src/EFCore/Metadata/Internal/Property.cs
@@ -161,7 +161,8 @@ public virtual void SetIsNullable(bool? nullable, ConfigurationSource configurat
}
}
- UpdateIsNullableConfigurationSource(configurationSource);
+ _isNullableConfigurationSource = configurationSource.Max(_isNullableConfigurationSource);
+
_isNullable = nullable;
if (isChanging)
@@ -180,9 +181,6 @@ public virtual void SetIsNullable(bool? nullable, ConfigurationSource configurat
///
public virtual ConfigurationSource? GetIsNullableConfigurationSource() => _isNullableConfigurationSource;
- private void UpdateIsNullableConfigurationSource(ConfigurationSource configurationSource)
- => _isNullableConfigurationSource = configurationSource.Max(_isNullableConfigurationSource);
-
///
/// 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
@@ -214,14 +212,9 @@ public virtual void SetValueGenerated(ValueGenerated? valueGenerated, Configurat
{
_valueGenerated = valueGenerated;
- if (valueGenerated == null)
- {
- _valueGeneratedConfigurationSource = null;
- }
- else
- {
- UpdateValueGeneratedConfigurationSource(configurationSource);
- }
+ _valueGeneratedConfigurationSource = valueGenerated == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_valueGeneratedConfigurationSource);
}
private static ValueGenerated DefaultValueGenerated => ValueGenerated.Never;
@@ -234,9 +227,6 @@ public virtual void SetValueGenerated(ValueGenerated? valueGenerated, Configurat
///
public virtual ConfigurationSource? GetValueGeneratedConfigurationSource() => _valueGeneratedConfigurationSource;
- private void UpdateValueGeneratedConfigurationSource(ConfigurationSource configurationSource)
- => _valueGeneratedConfigurationSource = configurationSource.Max(_valueGeneratedConfigurationSource);
-
///
/// 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
@@ -262,14 +252,9 @@ public virtual void SetIsConcurrencyToken(bool? concurrencyToken, ConfigurationS
_isConcurrencyToken = concurrencyToken;
}
- if (concurrencyToken == null)
- {
- _isConcurrencyTokenConfigurationSource = null;
- }
- else
- {
- UpdateIsConcurrencyTokenConfigurationSource(configurationSource);
- }
+ _isConcurrencyTokenConfigurationSource = concurrencyToken == null
+ ? (ConfigurationSource?)null
+ : configurationSource.Max(_isConcurrencyTokenConfigurationSource);
}
private static bool DefaultIsConcurrencyToken => false;
@@ -282,9 +267,6 @@ public virtual void SetIsConcurrencyToken(bool? concurrencyToken, ConfigurationS
///
public virtual ConfigurationSource? GetIsConcurrencyTokenConfigurationSource() => _isConcurrencyTokenConfigurationSource;
- private void UpdateIsConcurrencyTokenConfigurationSource(ConfigurationSource configurationSource)
- => _isConcurrencyTokenConfigurationSource = configurationSource.Max(_isConcurrencyTokenConfigurationSource);
-
///
/// 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
diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs
index 35a2480e16e..af7ac45e953 100644
--- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs
@@ -61,11 +61,13 @@ public void Test_new_annotations_handled_for_entity_types()
CoreAnnotationNames.DuplicateServiceProperties,
RelationalAnnotationNames.ColumnName,
RelationalAnnotationNames.ColumnType,
+ RelationalAnnotationNames.TableColumnMappings,
+ RelationalAnnotationNames.ViewColumnMappings,
RelationalAnnotationNames.DefaultValueSql,
RelationalAnnotationNames.ComputedColumnSql,
RelationalAnnotationNames.DefaultValue,
RelationalAnnotationNames.Name,
- RelationalAnnotationNames.SequencePrefix,
+ RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.DefaultSchema,
RelationalAnnotationNames.Filter,
@@ -145,10 +147,14 @@ public void Test_new_annotations_handled_for_properties()
CoreAnnotationNames.AmbiguousNavigations,
CoreAnnotationNames.DuplicateServiceProperties,
RelationalAnnotationNames.TableName,
+ RelationalAnnotationNames.ViewName,
RelationalAnnotationNames.Schema,
+ RelationalAnnotationNames.ViewSchema,
RelationalAnnotationNames.DefaultSchema,
+ RelationalAnnotationNames.TableMappings,
+ RelationalAnnotationNames.ViewMappings,
RelationalAnnotationNames.Name,
- RelationalAnnotationNames.SequencePrefix,
+ RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Filter,
RelationalAnnotationNames.DbFunction,
diff --git a/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs
index 6582c29197d..4466f5b348a 100644
--- a/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs
@@ -192,10 +192,30 @@ public void Can_diff_against_older_ownership_model(Type snapshotType)
Assert.Empty(differences);
}
+ [ConditionalTheory]
+ [InlineData(typeof(SequenceModelSnapshot1_1))]
+ [InlineData(typeof(SequenceModelSnapshot2_2))]
+ [InlineData(typeof(SequenceModelSnapshot3_1))]
+ public void Can_diff_against_older_sequence_model(Type snapshotType)
+ {
+ using var context = new SequenceContext();
+ var differ = context.GetService();
+ var snapshot = (ModelSnapshot)Activator.CreateInstance(snapshotType);
+ var reporter = new TestOperationReporter();
+ var processor = new SnapshotModelProcessor(reporter);
+
+ var differences = differ.GetDifferences(processor.Process(snapshot.Model), context.Model);
+
+ Assert.Empty(differences);
+ }
+
private void AddAnnotations(IMutableAnnotatable element)
{
foreach (var annotationName in GetAnnotationNames()
- .Where(a => a != RelationalAnnotationNames.MaxIdentifierLength)
+ .Where(a => a != RelationalAnnotationNames.MaxIdentifierLength
+#pragma warning disable CS0618 // Type or member is obsolete
+ && a != RelationalAnnotationNames.SequencePrefix)
+#pragma warning restore CS0618 // Type or member is obsolete
.Select(a => "Unicorn" + a.Substring(RelationalAnnotationNames.Prefix.Length - 1)))
{
element[annotationName] = "Value";
@@ -211,7 +231,10 @@ private void AssertAnnotations(IMutableAnnotatable element)
&& a != RelationalAnnotationNames.TableColumnMappings
&& a != RelationalAnnotationNames.Views
&& a != RelationalAnnotationNames.ViewMappings
- && a != RelationalAnnotationNames.ViewColumnMappings))
+ && a != RelationalAnnotationNames.ViewColumnMappings
+#pragma warning disable CS0618 // Type or member is obsolete
+ && a != RelationalAnnotationNames.SequencePrefix))
+#pragma warning restore CS0618 // Type or member is obsolete
{
Assert.Equal("Value", (string)element[annotationName]);
}
@@ -1163,6 +1186,63 @@ protected override void BuildModel(ModelBuilder modelBuilder)
#pragma warning restore 612, 618
}
}
+
+ private class SequenceModelSnapshot1_1 : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+ modelBuilder
+ .HasAnnotation("ChangeDetector.SkipDetectChanges", "true")
+ .HasAnnotation("ProductVersion", "1.1.6")
+ .HasAnnotation("Relational:Sequence:Bar.Foo", "'Foo', 'Bar', '2', '2', '1', '3', 'Int32', 'True'")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+ }
+ }
+
+ private class SequenceModelSnapshot2_2 : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ChangeDetector.SkipDetectChanges", "true")
+ .HasAnnotation("ProductVersion", "2.2.2-servicing-10034")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("Relational:Sequence:Bar.Foo", "'Foo', 'Bar', '2', '2', '1', '3', 'Int32', 'True'")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+#pragma warning restore 612, 618
+ }
+ }
+
+ private class SequenceModelSnapshot3_1 : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.1")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("Relational:Sequence:Bar.Foo", "'Foo', 'Bar', '2', '2', '1', '3', 'Int32', 'True'")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+#pragma warning restore 612, 618
+ }
+ }
+
+ private class SequenceContext : DbContext
+ {
+ protected override void OnConfiguring(DbContextOptionsBuilder options)
+ => options.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Ownership");
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.HasSequence("Foo", "Bar")
+ .StartsAt(2)
+ .HasMin(1)
+ .HasMax(3)
+ .IncrementsBy(2)
+ .IsCyclic();
+ }
+ }
}
}
diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
index 70181284111..5b395a2009e 100644
--- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
@@ -332,31 +332,6 @@ public void Views_are_ignored()
}
[ConditionalFact]
- public virtual void Sequence_is_stored_in_snapshot_as_annotations()
- {
- Test(
- builder =>
- {
- builder.HasSequence("Foo", "Bar")
- .StartsAt(2)
- .HasMin(1)
- .HasMax(3)
- .IncrementsBy(2)
- .IsCyclic();
- },
- AddBoilerPlate(
- @"
- modelBuilder
- .HasAnnotation(""Relational:MaxIdentifierLength"", 128)
- .HasAnnotation(""Relational:Sequence:Bar.Foo"", ""'Foo', 'Bar', '2', '2', '1', '3', 'Int32', 'True'"")
- .HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);"),
- o =>
- {
- Assert.Equal(3, o.GetAnnotations().Count());
- });
- }
-
- [ConditionalFact(Skip = "Issue #14103")]
public virtual void Sequence_is_stored_in_snapshot_as_fluent_api()
{
Test(
@@ -370,15 +345,14 @@ public virtual void Sequence_is_stored_in_snapshot_as_fluent_api()
.IsCyclic();
},
AddBoilerPlate(
- @"
- modelBuilder
- .HasAnnotation(""Relational:MaxIdentifierLength"", 128)
- .HasSequence(""Foo"", ""Bar"")
- .StartsAt(2)
- .HasMin(1)
- .HasMax(3)
- .IncrementsBy(2)
- .IsCyclic();"),
+ GetHeading()
+ + @"
+ modelBuilder.HasSequence(""Foo"", ""Bar"")
+ .StartsAt(2L)
+ .IncrementsBy(2)
+ .HasMin(1L)
+ .HasMax(3L)
+ .IsCyclic();"),
o =>
{
Assert.Equal(3, o.GetAnnotations().Count());
diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalMetadataExtensionsTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalMetadataExtensionsTest.cs
index 5c49a782a8f..2c0a3698ba8 100644
--- a/test/EFCore.Relational.Tests/Metadata/RelationalMetadataExtensionsTest.cs
+++ b/test/EFCore.Relational.Tests/Metadata/RelationalMetadataExtensionsTest.cs
@@ -2,6 +2,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 System.Reflection;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
@@ -583,7 +584,7 @@ public void Can_get_multiple_sequences()
var sequences = model.GetSequences();
- Assert.Equal(2, sequences.Count);
+ Assert.Equal(2, sequences.Count());
Assert.Contains(sequences, s => s.Name == "Fibonacci");
Assert.Contains(sequences, s => s.Name == "Golomb");
}
diff --git a/test/EFCore.Relational.Tests/Metadata/SequenceTest.cs b/test/EFCore.Relational.Tests/Metadata/SequenceTest.cs
index 1c58be9a6d3..b0f4adcc3cf 100644
--- a/test/EFCore.Relational.Tests/Metadata/SequenceTest.cs
+++ b/test/EFCore.Relational.Tests/Metadata/SequenceTest.cs
@@ -13,7 +13,9 @@ public class SequenceTest
[ConditionalFact]
public void Can_be_created_with_default_values()
{
- var sequence = ((IMutableModel)new Model()).AddSequence("Foo");
+ IMutableModel model = new Model();
+
+ var sequence = model.AddSequence("Foo");
Assert.Equal("Foo", sequence.Name);
Assert.Null(sequence.Schema);
@@ -22,17 +24,37 @@ public void Can_be_created_with_default_values()
Assert.Null(sequence.MinValue);
Assert.Null(sequence.MaxValue);
Assert.Same(typeof(long), sequence.ClrType);
+ Assert.False(sequence.IsCyclic);
+ Assert.Same(model, sequence.Model);
+
+ model.SetDefaultSchema("db0");
+
+ Assert.Equal("db0", sequence.Schema);
+
+ var conventionSequence = (IConventionSequence)sequence;
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetConfigurationSource());
+ Assert.Null(conventionSequence.GetIncrementByConfigurationSource());
+ Assert.Null(conventionSequence.GetStartValueConfigurationSource());
+ Assert.Null(conventionSequence.GetMinValueConfigurationSource());
+ Assert.Null(conventionSequence.GetMaxValueConfigurationSource());
+ Assert.Null(conventionSequence.GetClrTypeConfigurationSource());
+ Assert.Null(conventionSequence.GetIsCyclicConfigurationSource());
}
[ConditionalFact]
public void Can_be_created_with_specified_values()
{
- var sequence = new Model().AddSequence("Foo", "Smoo");
+ IMutableModel model = new Model();
+
+ model.SetDefaultSchema("db0");
+
+ var sequence = model.AddSequence("Foo", "Smoo");
sequence.StartValue = 1729;
sequence.IncrementBy = 11;
sequence.MinValue = 2001;
sequence.MaxValue = 2010;
sequence.ClrType = typeof(int);
+ sequence.IsCyclic = true;
Assert.Equal("Foo", sequence.Name);
Assert.Equal("Smoo", sequence.Schema);
@@ -41,6 +63,15 @@ public void Can_be_created_with_specified_values()
Assert.Equal(2001, sequence.MinValue);
Assert.Equal(2010, sequence.MaxValue);
Assert.Same(typeof(int), sequence.ClrType);
+
+ var conventionSequence = (IConventionSequence)sequence;
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetConfigurationSource());
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetIncrementByConfigurationSource());
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetStartValueConfigurationSource());
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetMinValueConfigurationSource());
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetMaxValueConfigurationSource());
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetClrTypeConfigurationSource());
+ Assert.Equal(ConfigurationSource.Explicit, conventionSequence.GetIsCyclicConfigurationSource());
}
[ConditionalFact]
@@ -63,120 +94,5 @@ public void Can_only_be_created_for_byte_short_int_and_long_decimal()
Assert.Throws(
() => sequence.ClrType = typeof(bool)).Message);
}
-
- [ConditionalFact]
- public void Can_get_model()
- {
- IMutableModel model = new Model();
-
- var sequence = model.AddSequence("Foo");
-
- Assert.Same(model, sequence.Model);
- }
-
- [ConditionalFact]
- public void Can_get_model_default_schema_if_sequence_schema_not_specified()
- {
- IMutableModel model = new Model();
-
- var sequence = model.AddSequence("Foo");
-
- Assert.Null(sequence.Schema);
-
- model.SetDefaultSchema("db0");
-
- Assert.Equal("db0", sequence.Schema);
- }
-
- [ConditionalFact]
- public void Can_get_sequence_schema_if_specified_explicitly()
- {
- IMutableModel model = new Model();
-
- model.SetDefaultSchema("db0");
- var sequence = model.AddSequence("Foo", "db1");
-
- Assert.Equal("db1", sequence.Schema);
- }
-
- [ConditionalFact]
- public void Can_serialize_and_deserialize()
- {
- IMutableModel model = new Model();
- var sequence = model.AddSequence("Foo", "Smoo");
- sequence.StartValue = 1729;
- sequence.IncrementBy = 11;
- sequence.MinValue = 2001;
- sequence.MaxValue = 2010;
- sequence.ClrType = typeof(int);
-
- model.FindSequence("Foo", "Smoo");
-
- Assert.Equal("Foo", sequence.Name);
- Assert.Equal("Smoo", sequence.Schema);
- Assert.Equal(11, sequence.IncrementBy);
- Assert.Equal(1729, sequence.StartValue);
- Assert.Equal(2001, sequence.MinValue);
- Assert.Equal(2010, sequence.MaxValue);
- Assert.Same(typeof(int), sequence.ClrType);
- }
-
- [ConditionalFact]
- public void Can_serialize_and_deserialize_with_defaults()
- {
- IMutableModel model = new Model();
- model.AddSequence("Foo");
-
- var sequence = model.FindSequence("Foo");
-
- Assert.Equal("Foo", sequence.Name);
- Assert.Null(sequence.Schema);
- Assert.Equal(1, sequence.IncrementBy);
- Assert.Equal(1, sequence.StartValue);
- Assert.Null(sequence.MinValue);
- Assert.Null(sequence.MaxValue);
- Assert.Same(typeof(long), sequence.ClrType);
- }
-
- [ConditionalFact]
- public void Can_serialize_and_deserialize_with_funky_names()
- {
- IMutableModel model = new Model();
- var sequence = model.AddSequence("'Foo'", "''S'''m'oo'''");
- sequence.StartValue = 1729;
- sequence.IncrementBy = 11;
- sequence.ClrType = typeof(int);
-
- sequence = model.FindSequence("'Foo'", "''S'''m'oo'''");
-
- Assert.Equal("'Foo'", sequence.Name);
- Assert.Equal("''S'''m'oo'''", sequence.Schema);
- Assert.Equal(11, sequence.IncrementBy);
- Assert.Equal(1729, sequence.StartValue);
- Assert.Null(sequence.MinValue);
- Assert.Null(sequence.MaxValue);
- Assert.Same(typeof(int), sequence.ClrType);
- }
-
- [ConditionalFact]
- public void Throws_on_bad_serialized_form()
- {
- IMutableModel model = new Model();
- var sequence = model.AddSequence("Foo", "Smoo");
- sequence.StartValue = 1729;
- sequence.IncrementBy = 11;
- sequence.MinValue = 2001;
- sequence.MaxValue = 2010;
- sequence.ClrType = typeof(int);
-
- var annotationName = RelationalAnnotationNames.SequencePrefix + "Smoo.Foo";
-
- model[annotationName] = ((string)model[annotationName]).Replace("1", "Z");
-
- Assert.Equal(
- RelationalStrings.BadSequenceString,
- Assert.Throws(
- () => model.FindSequence("Foo", "Smoo").ClrType).Message);
- }
}
}
diff --git a/test/EFCore.SqlServer.Tests/Metadata/Conventions/SqlServerValueGenerationStrategyConventionTest.cs b/test/EFCore.SqlServer.Tests/Metadata/Conventions/SqlServerValueGenerationStrategyConventionTest.cs
index bfbe7dfc6f0..def2b65d273 100644
--- a/test/EFCore.SqlServer.Tests/Metadata/Conventions/SqlServerValueGenerationStrategyConventionTest.cs
+++ b/test/EFCore.SqlServer.Tests/Metadata/Conventions/SqlServerValueGenerationStrategyConventionTest.cs
@@ -40,7 +40,7 @@ public void Annotations_are_added_when_conventional_model_builder_is_used_with_s
Assert.Equal(RelationalAnnotationNames.MaxIdentifierLength, annotations[0].Name);
Assert.Equal(
- RelationalAnnotationNames.SequencePrefix + "." + SqlServerModelExtensions.DefaultHiLoSequenceName,
+ RelationalAnnotationNames.Sequences,
annotations[1].Name);
Assert.NotNull(annotations[1].Value);
diff --git a/test/EFCore.SqlServer.Tests/Metadata/SqlServerMetadataExtensionsTest.cs b/test/EFCore.SqlServer.Tests/Metadata/SqlServerMetadataExtensionsTest.cs
index 791f514e670..7f8fface526 100644
--- a/test/EFCore.SqlServer.Tests/Metadata/SqlServerMetadataExtensionsTest.cs
+++ b/test/EFCore.SqlServer.Tests/Metadata/SqlServerMetadataExtensionsTest.cs
@@ -190,146 +190,6 @@ public void Can_get_and_set_key_clustering()
Assert.Null(key.IsClustered());
}
- [ConditionalFact]
- public void Can_get_and_set_sequence()
- {
- var modelBuilder = GetModelBuilder();
- var model = modelBuilder.Model;
-
- Assert.Null(model.FindSequence("Foo"));
- Assert.Null(model.FindSequence("Foo"));
- Assert.Null(((IModel)model).FindSequence("Foo"));
-
- var sequence = model.AddSequence("Foo");
-
- Assert.Equal("Foo", model.FindSequence("Foo").Name);
- Assert.Equal("Foo", ((IModel)model).FindSequence("Foo").Name);
- Assert.Equal("Foo", model.FindSequence("Foo").Name);
- Assert.Equal("Foo", ((IModel)model).FindSequence("Foo").Name);
-
- Assert.Equal("Foo", sequence.Name);
- Assert.Null(sequence.Schema);
- Assert.Equal(1, sequence.IncrementBy);
- Assert.Equal(1, sequence.StartValue);
- Assert.Null(sequence.MinValue);
- Assert.Null(sequence.MaxValue);
- Assert.Same(typeof(long), sequence.ClrType);
-
- Assert.NotNull(model.FindSequence("Foo"));
-
- var sequence2 = model.FindSequence("Foo");
-
- sequence.StartValue = 1729;
- sequence.IncrementBy = 11;
- sequence.MinValue = 2001;
- sequence.MaxValue = 2010;
- sequence.ClrType = typeof(int);
-
- Assert.Equal("Foo", sequence.Name);
- Assert.Null(sequence.Schema);
- Assert.Equal(11, sequence.IncrementBy);
- Assert.Equal(1729, sequence.StartValue);
- Assert.Equal(2001, sequence.MinValue);
- Assert.Equal(2010, sequence.MaxValue);
- Assert.Same(typeof(int), sequence.ClrType);
-
- Assert.Equal(sequence2.Name, sequence.Name);
- Assert.Equal(sequence2.Schema, sequence.Schema);
- Assert.Equal(sequence2.IncrementBy, sequence.IncrementBy);
- Assert.Equal(sequence2.StartValue, sequence.StartValue);
- Assert.Equal(sequence2.MinValue, sequence.MinValue);
- Assert.Equal(sequence2.MaxValue, sequence.MaxValue);
- Assert.Same(sequence2.ClrType, sequence.ClrType);
- }
-
- [ConditionalFact]
- public void Can_get_and_set_sequence_with_schema_name()
- {
- var modelBuilder = GetModelBuilder();
- var model = modelBuilder.Model;
-
- Assert.Null(model.FindSequence("Foo", "Smoo"));
- Assert.Null(model.FindSequence("Foo", "Smoo"));
- Assert.Null(((IModel)model).FindSequence("Foo", "Smoo"));
-
- var sequence = model.AddSequence("Foo", "Smoo");
-
- Assert.Equal("Foo", model.FindSequence("Foo", "Smoo").Name);
- Assert.Equal("Foo", ((IModel)model).FindSequence("Foo", "Smoo").Name);
- Assert.Equal("Foo", model.FindSequence("Foo", "Smoo").Name);
- Assert.Equal("Foo", ((IModel)model).FindSequence("Foo", "Smoo").Name);
-
- Assert.Equal("Foo", sequence.Name);
- Assert.Equal("Smoo", sequence.Schema);
- Assert.Equal(1, sequence.IncrementBy);
- Assert.Equal(1, sequence.StartValue);
- Assert.Null(sequence.MinValue);
- Assert.Null(sequence.MaxValue);
- Assert.Same(typeof(long), sequence.ClrType);
-
- Assert.NotNull(model.FindSequence("Foo", "Smoo"));
-
- var sequence2 = model.FindSequence("Foo", "Smoo");
-
- sequence.StartValue = 1729;
- sequence.IncrementBy = 11;
- sequence.MinValue = 2001;
- sequence.MaxValue = 2010;
- sequence.ClrType = typeof(int);
-
- Assert.Equal("Foo", sequence.Name);
- Assert.Equal("Smoo", sequence.Schema);
- Assert.Equal(11, sequence.IncrementBy);
- Assert.Equal(1729, sequence.StartValue);
- Assert.Equal(2001, sequence.MinValue);
- Assert.Equal(2010, sequence.MaxValue);
- Assert.Same(typeof(int), sequence.ClrType);
-
- Assert.Equal(sequence2.Name, sequence.Name);
- Assert.Equal(sequence2.Schema, sequence.Schema);
- Assert.Equal(sequence2.IncrementBy, sequence.IncrementBy);
- Assert.Equal(sequence2.StartValue, sequence.StartValue);
- Assert.Equal(sequence2.MinValue, sequence.MinValue);
- Assert.Equal(sequence2.MaxValue, sequence.MaxValue);
- Assert.Same(sequence2.ClrType, sequence.ClrType);
- }
-
- [ConditionalFact]
- public void Can_get_multiple_sequences()
- {
- var modelBuilder = GetModelBuilder();
- var model = modelBuilder.Model;
-
- model.AddSequence("Fibonacci");
- model.AddSequence("Golomb");
-
- var sequences = model.GetSequences();
-
- Assert.Equal(2, sequences.Count);
- Assert.Contains(sequences, s => s.Name == "Fibonacci");
- Assert.Contains(sequences, s => s.Name == "Golomb");
- }
-
- [ConditionalFact]
- public void Can_get_multiple_sequences_when_overridden()
- {
- var modelBuilder = GetModelBuilder();
- var model = modelBuilder.Model;
-
- model.AddSequence("Fibonacci").StartValue = 1;
- model.FindSequence("Fibonacci").StartValue = 3;
- model.AddSequence("Golomb");
-
- var sequences = model.GetSequences();
-
- Assert.Equal(2, sequences.Count);
- Assert.Contains(sequences, s => s.Name == "Golomb");
-
- var sequence = sequences.FirstOrDefault(s => s.Name == "Fibonacci");
- Assert.NotNull(sequence);
- Assert.Equal(3, sequence.StartValue);
- }
-
[ConditionalFact]
public void Can_get_and_set_value_generation_on_model()
{