Skip to content

Commit

Permalink
Store all sequences in a single annotation
Browse files Browse the repository at this point in the history
Fixes #14103
  • Loading branch information
AndriySvyryd committed Feb 26, 2020
1 parent 659ecfd commit 04dece9
Show file tree
Hide file tree
Showing 16 changed files with 438 additions and 483 deletions.
93 changes: 93 additions & 0 deletions src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
}

Expand Down Expand Up @@ -338,6 +344,93 @@ protected virtual void GenerateBaseType(
}
}

/// <summary>
/// Generates code for an <see cref="ISequence" />.
/// </summary>
/// <param name="builderName"> The name of the builder variable. </param>
/// <param name="sequence"> The sequence. </param>
/// <param name="stringBuilder"> The builder code is added to. </param>
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(";");
}

/// <summary>
/// Generates code for <see cref="IProperty" /> objects.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> it
CoreAnnotationNames.DefiningQuery,
CoreAnnotationNames.QueryFilter,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.TableColumnMappings,
Expand All @@ -252,7 +253,7 @@ private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> it

var ignoredAnnotationTypes = new List<string>
{
RelationalAnnotationNames.DbFunction, RelationalAnnotationNames.SequencePrefix
RelationalAnnotationNames.DbFunction
};

return items.SelectMany(
Expand Down
30 changes: 29 additions & 1 deletion src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())
{
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IAnnotation>();
annotationsToRemove.AddRange(
annotations.Where(
a => a.Name.StartsWith(RelationalAnnotationNames.SequencePrefix, StringComparison.Ordinal)));

var lines = new List<string>();

Expand Down
23 changes: 11 additions & 12 deletions src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
26 changes: 11 additions & 15 deletions src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,8 @@ public static void SetMaxIdentifierLength([NotNull] this IConventionModel model,
/// the given schema was found.
/// </returns>
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)));

/// <summary>
/// Finds an <see cref="IMutableSequence" /> with the given name.
Expand Down Expand Up @@ -194,7 +190,7 @@ public static IConventionSequence FindSequence(
/// <returns> The sequence. </returns>
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);

/// <summary>
/// Either returns the existing <see cref="IMutableSequence" /> with the given name in the given schema
Expand All @@ -207,7 +203,7 @@ public static IMutableSequence AddSequence(
/// <returns> The sequence. </returns>
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);

Expand All @@ -223,7 +219,7 @@ public static IConventionSequence AddSequence(
/// </returns>
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);

/// <summary>
/// Removes the <see cref="IConventionSequence" /> with the given name.
Expand All @@ -243,22 +239,22 @@ public static IConventionSequence RemoveSequence(
/// Returns all <see cref="ISequence" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the sequences in. </param>
public static IReadOnlyList<ISequence> GetSequences([NotNull] this IModel model)
=> Sequence.GetSequences(model, RelationalAnnotationNames.SequencePrefix).ToList();
public static IEnumerable<ISequence> GetSequences([NotNull] this IModel model)
=> Sequence.GetSequences(model);

/// <summary>
/// Returns all <see cref="IMutableSequence" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the sequences in. </param>
public static IReadOnlyList<IMutableSequence> GetSequences([NotNull] this IMutableModel model)
=> (IReadOnlyList<IMutableSequence>)((IModel)model).GetSequences();
public static IEnumerable<IMutableSequence> GetSequences([NotNull] this IMutableModel model)
=> (IEnumerable<IMutableSequence>)((IModel)model).GetSequences();

/// <summary>
/// Returns all <see cref="IConventionSequence" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the sequences in. </param>
public static IReadOnlyList<IConventionSequence> GetSequences([NotNull] this IConventionModel model)
=> (IReadOnlyList<IConventionSequence>)((IModel)model).GetSequences();
public static IEnumerable<IConventionSequence> GetSequences([NotNull] this IConventionModel model)
=> (IEnumerable<IConventionSequence>)((IModel)model).GetSequences();

/// <summary>
/// Finds a <see cref="IDbFunction" /> that is mapped to the method represented by the given <see cref="MethodInfo" />.
Expand Down
Loading

0 comments on commit 04dece9

Please sign in to comment.