Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sequence-based value generation, by default for TPC keys #2456

Merged
merged 2 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<Copyright>Copyright 2022 © The Npgsql Development Team</Copyright>
<Company>Npgsql</Company>
<VersionPrefix>7.0.0-preview.7</VersionPrefix>
<VersionPrefix>7.0.0-rc.1</VersionPrefix>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageLicenseExpression>PostgreSQL</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/npgsql/efcore.pg</PackageProjectUrl>
Expand Down
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<EFCoreVersion>7.0.0-preview.7.22376.2</EFCoreVersion>
<MicrosoftExtensionsVersion>7.0.0-preview.7.22375.6</MicrosoftExtensionsVersion>
<EFCoreVersion>7.0.0-rc.1.22378.4</EFCoreVersion>
<MicrosoftExtensionsVersion>7.0.0-rc.1.22374.4</MicrosoftExtensionsVersion>
<NpgsqlVersion>7.0.0-preview.6</NpgsqlVersion>
</PropertyGroup>

Expand Down
204 changes: 113 additions & 91 deletions src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public static ModelBuilder UseHiLo(this ModelBuilder modelBuilder, string? name
model.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.SequenceHiLo);
model.SetHiLoSequenceName(name);
model.SetHiLoSequenceSchema(schema);
model.SetSequenceNameSuffix(null);
model.SetSequenceSchema(null);

return modelBuilder;
}
Expand Down Expand Up @@ -138,11 +140,13 @@ public static ModelBuilder UseIdentityAlwaysColumns(this ModelBuilder modelBuild
{
Check.NotNull(modelBuilder, nameof(modelBuilder));

var property = modelBuilder.Model;
var model = modelBuilder.Model;

property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityAlwaysColumn);
property.SetHiLoSequenceName(null);
property.SetHiLoSequenceSchema(null);
model.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityAlwaysColumn);
model.SetSequenceNameSuffix(null);
model.SetSequenceSchema(null);
model.SetHiLoSequenceName(null);
model.SetHiLoSequenceSchema(null);

return modelBuilder;
}
Expand All @@ -164,11 +168,13 @@ public static ModelBuilder UseIdentityByDefaultColumns(this ModelBuilder modelBu
{
Check.NotNull(modelBuilder, nameof(modelBuilder));

var property = modelBuilder.Model;
var model = modelBuilder.Model;

property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
property.SetHiLoSequenceName(null);
property.SetHiLoSequenceSchema(null);
model.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
model.SetSequenceNameSuffix(null);
model.SetSequenceSchema(null);
model.SetHiLoSequenceName(null);
model.SetHiLoSequenceSchema(null);

return modelBuilder;
}
Expand Down Expand Up @@ -203,15 +209,25 @@ public static ModelBuilder UseIdentityColumns(this ModelBuilder modelBuilder)
NpgsqlValueGenerationStrategy? valueGenerationStrategy,
bool fromDataAnnotation = false)
{
if (modelBuilder.CanSetAnnotation(
NpgsqlAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy, fromDataAnnotation))
if (modelBuilder.CanSetValueGenerationStrategy(valueGenerationStrategy, fromDataAnnotation))
{
modelBuilder.Metadata.SetValueGenerationStrategy(valueGenerationStrategy, fromDataAnnotation);

if (valueGenerationStrategy != NpgsqlValueGenerationStrategy.SequenceHiLo)
{
modelBuilder.HasHiLoSequence(null, null, fromDataAnnotation);
}

if (valueGenerationStrategy != NpgsqlValueGenerationStrategy.Sequence)
{
if (modelBuilder.CanSetAnnotation(NpgsqlAnnotationNames.SequenceNameSuffix, null)
&& modelBuilder.CanSetAnnotation(NpgsqlAnnotationNames.SequenceSchema, null))
{
modelBuilder.Metadata.SetSequenceNameSuffix(null, fromDataAnnotation);
modelBuilder.Metadata.SetSequenceSchema(null, fromDataAnnotation);
}
}

return modelBuilder;
}

Expand All @@ -238,6 +254,39 @@ public static bool CanSetValueGenerationStrategy(

#endregion Identity

#region Sequence

/// <summary>
/// Configures the model to use a sequence per hierarchy to generate values for key properties marked as
/// <see cref="ValueGenerated.OnAdd" />, when targeting PostgreSQL.
/// </summary>
/// <param name="modelBuilder">The model builder.</param>
/// <param name="nameSuffix">The name that will suffix the table name for each sequence created automatically.</param>
/// <param name="schema">The schema of the sequence.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static ModelBuilder UseKeySequences(
this ModelBuilder modelBuilder,
string? nameSuffix = null,
string? schema = null)
{
Check.NullButNotEmpty(nameSuffix, nameof(nameSuffix));
Check.NullButNotEmpty(schema, nameof(schema));

var model = modelBuilder.Model;

nameSuffix ??= NpgsqlModelExtensions.DefaultSequenceNameSuffix;

model.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.Sequence);
model.SetSequenceNameSuffix(nameSuffix);
model.SetSequenceSchema(schema);
model.SetHiLoSequenceName(null);
model.SetHiLoSequenceSchema(null);

return modelBuilder;
}

#endregion Sequence

#region Extensions

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public static PropertyBuilder UseHiLo(
property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.SequenceHiLo);
property.SetHiLoSequenceName(name);
property.SetHiLoSequenceSchema(schema);
property.SetSequenceName(null);
property.SetSequenceSchema(null);
property.RemoveIdentityOptions();

return propertyBuilder;
Expand Down Expand Up @@ -115,6 +117,106 @@ public static bool CanSetHiLoSequence(

#endregion HiLo

#region Sequence

/// <summary>
/// Configures the key property to use a sequence-based key value generation pattern to generate values for new entities,
/// when targeting PostgreSQL. This method sets the property to be <see cref="ValueGenerated.OnAdd" />.
/// </summary>
/// <param name="propertyBuilder">The builder for the property being configured.</param>
/// <param name="name">The name of the sequence.</param>
/// <param name="schema">The schema of the sequence.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static PropertyBuilder UseSequence(
this PropertyBuilder propertyBuilder,
string? name = null,
string? schema = null)
{
Check.NullButNotEmpty(name, nameof(name));
Check.NullButNotEmpty(schema, nameof(schema));

var property = propertyBuilder.Metadata;

property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.Sequence);
property.SetSequenceName(name);
property.SetSequenceSchema(schema);
property.SetHiLoSequenceName(null);
property.SetHiLoSequenceSchema(null);

return propertyBuilder;
}

/// <summary>
/// Configures the key property to use a sequence-based key value generation pattern to generate values for new entities,
/// when targeting SQL Server. This method sets the property to be <see cref="ValueGenerated.OnAdd" />.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
/// <see href="https://aka.ms/efcore-docs-Npgsql">Accessing SQL Server and SQL Azure databases with EF Core</see>
/// for more information and examples.
/// </remarks>
/// <typeparam name="TProperty">The type of the property being configured.</typeparam>
/// <param name="propertyBuilder">The builder for the property being configured.</param>
/// <param name="name">The name of the sequence.</param>
/// <param name="schema">The schema of the sequence.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static PropertyBuilder<TProperty> UseSequence<TProperty>(
this PropertyBuilder<TProperty> propertyBuilder,
string? name = null,
string? schema = null)
=> (PropertyBuilder<TProperty>)UseSequence((PropertyBuilder)propertyBuilder, name, schema);

/// <summary>
/// Configures the database sequence used for the key value generation pattern to generate values for the key property,
/// when targeting PostgreSQL.
/// </summary>
/// <param name="propertyBuilder">The builder for the property being configured.</param>
/// <param name="name">The name of the sequence.</param>
/// <param name="schema">The schema of the sequence.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>A builder to further configure the sequence.</returns>
public static IConventionSequenceBuilder? HasSequence(
this IConventionPropertyBuilder propertyBuilder,
string? name,
string? schema,
bool fromDataAnnotation = false)
{
if (!propertyBuilder.CanSetSequence(name, schema, fromDataAnnotation))
{
return null;
}

propertyBuilder.Metadata.SetSequenceName(name, fromDataAnnotation);
propertyBuilder.Metadata.SetSequenceSchema(schema, fromDataAnnotation);

return name == null
? null
: propertyBuilder.Metadata.DeclaringEntityType.Model.Builder.HasSequence(name, schema, fromDataAnnotation);
}

/// <summary>
/// Returns a value indicating whether the given name and schema can be set for the key value generation sequence.
/// </summary>
/// <param name="propertyBuilder">The builder for the property being configured.</param>
/// <param name="name">The name of the sequence.</param>
/// <param name="schema">The schema of the sequence.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the given name and schema can be set for the key value generation sequence.</returns>
public static bool CanSetSequence(
this IConventionPropertyBuilder propertyBuilder,
string? name,
string? schema,
bool fromDataAnnotation = false)
{
Check.NullButNotEmpty(name, nameof(name));
Check.NullButNotEmpty(schema, nameof(schema));

return propertyBuilder.CanSetAnnotation(NpgsqlAnnotationNames.SequenceName, name, fromDataAnnotation)
&& propertyBuilder.CanSetAnnotation(NpgsqlAnnotationNames.SequenceSchema, schema, fromDataAnnotation);
}

#endregion Sequence

#region Serial

/// <summary>
Expand All @@ -133,8 +235,8 @@ public static PropertyBuilder UseSerialColumn(

var property = propertyBuilder.Metadata;
property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.SerialColumn);
property.SetHiLoSequenceName(null);
property.SetHiLoSequenceSchema(null);
property.SetSequenceName(null);
property.SetSequenceSchema(null);
property.RemoveHiLoOptions();
property.RemoveIdentityOptions();

Expand Down Expand Up @@ -178,6 +280,8 @@ public static PropertyBuilder UseIdentityAlwaysColumn(this PropertyBuilder prope
property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityAlwaysColumn);
property.SetHiLoSequenceName(null);
property.SetHiLoSequenceSchema(null);
property.SetSequenceName(null);
property.SetSequenceSchema(null);

return propertyBuilder;
}
Expand Down Expand Up @@ -222,6 +326,8 @@ public static PropertyBuilder UseIdentityByDefaultColumn(this PropertyBuilder pr
property.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
property.SetHiLoSequenceName(null);
property.SetHiLoSequenceSchema(null);
property.SetSequenceName(null);
property.SetSequenceSchema(null);

return propertyBuilder;
}
Expand Down Expand Up @@ -303,11 +409,17 @@ public static PropertyBuilder<TProperty> UseIdentityColumn<TProperty>(
NpgsqlAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy, fromDataAnnotation))
{
propertyBuilder.Metadata.SetValueGenerationStrategy(valueGenerationStrategy, fromDataAnnotation);

if (valueGenerationStrategy != NpgsqlValueGenerationStrategy.SequenceHiLo)
{
propertyBuilder.HasHiLoSequence(null, null, fromDataAnnotation);
}

if (valueGenerationStrategy != NpgsqlValueGenerationStrategy.Sequence)
{
propertyBuilder.HasSequence(null, null, fromDataAnnotation);
}

return propertyBuilder;
}

Expand Down
Loading