Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,53 @@ public override IReadOnlyList<MethodCallCodeFragment> GenerateFluentApiCalls(
IProperty property,
IDictionary<string, IAnnotation> annotations)
{
var defaultConstraintNameAnnotation = default(IAnnotation);
var defaultValueAnnotation = default(IAnnotation);
var defaultValueSqlAnnotation = default(IAnnotation);

// named default constraint must be handled on the provider level, so removing the annotations before calling base
if (annotations.TryGetValue(SqlServerAnnotationNames.DefaultConstraintName, out defaultConstraintNameAnnotation))
{
if (defaultConstraintNameAnnotation.Value as string != string.Empty)
{
if (annotations.TryGetValue(RelationalAnnotationNames.DefaultValue, out defaultValueAnnotation))
{
annotations.Remove(RelationalAnnotationNames.DefaultValue);
}
else
{
var defaultValueSqlAnnotationExists = annotations.TryGetValue(RelationalAnnotationNames.DefaultValueSql, out defaultValueSqlAnnotation);
Check.DebugAssert(defaultValueSqlAnnotationExists, "If default constaint name was set, one of DefaultValue or DefaultValueSql must also be set.");
annotations.Remove(RelationalAnnotationNames.DefaultValueSql);
}
}

annotations.Remove(SqlServerAnnotationNames.DefaultConstraintName);
}

var fragments = new List<MethodCallCodeFragment>(base.GenerateFluentApiCalls(property, annotations));

if (defaultConstraintNameAnnotation != null && defaultConstraintNameAnnotation.Value as string != string.Empty)
{
if (defaultValueAnnotation != null)
{
fragments.Add(
new MethodCallCodeFragment(
nameof(SqlServerPropertyBuilderExtensions.HasDefaultValue),
defaultValueAnnotation.Value,
defaultConstraintNameAnnotation.Value));
}
else
{
Check.NotNull(defaultValueSqlAnnotation, "Both DefaultValue and DefaultValueSql annotations are null.");
fragments.Add(
new MethodCallCodeFragment(
nameof(SqlServerPropertyBuilderExtensions.HasDefaultValueSql),
defaultValueSqlAnnotation.Value,
defaultConstraintNameAnnotation.Value));
}
}

var isPrimitiveCollection = property.IsPrimitiveCollection;

if (GenerateValueGenerationStrategy(annotations, property.DeclaringType.Model, onModel: false, complexType: property.DeclaringType is IComplexType) is MethodCallCodeFragment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public override void Generate(IColumn column, CSharpRuntimeAnnotationCodeGenerat
annotations.Remove(SqlServerAnnotationNames.Sparse);
annotations.Remove(SqlServerAnnotationNames.TemporalIsPeriodStartColumn);
annotations.Remove(SqlServerAnnotationNames.TemporalIsPeriodEndColumn);
annotations.Remove(SqlServerAnnotationNames.DefaultConstraintName);
}

base.Generate(column, parameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,4 +651,42 @@ public static bool CanSetPerformanceLevelSql(
string? performanceLevel,
bool fromDataAnnotation = false)
=> modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.PerformanceLevelSql, performanceLevel, fromDataAnnotation);

/// <summary>
/// TODO
/// </summary>
public static ModelBuilder UseNamedDefaultConstraints(this ModelBuilder modelBuilder, bool value = true)
{
Check.NotNull(value, nameof(value));

modelBuilder.Model.UseNamedDefaultConstraints(value);

return modelBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static IConventionModelBuilder? UseNamedDefaultConstraints(
this IConventionModelBuilder modelBuilder,
bool value,
bool fromDataAnnotation = false)
{
if (modelBuilder.CanUseNamedDefaultConstraints(value, fromDataAnnotation))
{
modelBuilder.Metadata.UseNamedDefaultConstraints(value, fromDataAnnotation);
return modelBuilder;
}

return null;
}

/// <summary>
/// TODO
/// </summary>
public static bool CanUseNamedDefaultConstraints(
this IConventionModelBuilder modelBuilder,
bool value,
bool fromDataAnnotation = false)
=> modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.UseNamedDefaultConstraints, value, fromDataAnnotation);
}
32 changes: 32 additions & 0 deletions src/EFCore.SqlServer/Extensions/SqlServerModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -472,4 +472,36 @@ public static void SetPerformanceLevelSql(this IMutableModel model, string? valu
/// <returns>The <see cref="ConfigurationSource" /> for the performance level of the database.</returns>
public static ConfigurationSource? GetPerformanceLevelSqlConfigurationSource(this IConventionModel model)
=> model.FindAnnotation(SqlServerAnnotationNames.PerformanceLevelSql)?.GetConfigurationSource();

/// <summary>
/// TODO
/// </summary>
public static bool? AreNamedDefaultConstraintsUsed(this IReadOnlyModel model)
=> (model is RuntimeModel)
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
: (bool?)model[SqlServerAnnotationNames.UseNamedDefaultConstraints];

/// <summary>
/// TODO
/// </summary>
public static void UseNamedDefaultConstraints(this IMutableModel model, bool value)
=> model.SetOrRemoveAnnotation(SqlServerAnnotationNames.UseNamedDefaultConstraints, value);

/// <summary>
/// TODO
/// </summary>
public static bool? UseNamedDefaultConstraints(
this IConventionModel model,
bool value,
bool fromDataAnnotation = false)
=> (bool?)model.SetOrRemoveAnnotation(
SqlServerAnnotationNames.UseNamedDefaultConstraints,
value,
fromDataAnnotation)?.Value;

/// <summary>
/// TODO
/// </summary>
public static ConfigurationSource? UseNamedDefaultConstraintsConfigurationSource(this IConventionModel model)
=> model.FindAnnotation(SqlServerAnnotationNames.UseNamedDefaultConstraints)?.GetConfigurationSource();
}
Original file line number Diff line number Diff line change
Expand Up @@ -812,4 +812,120 @@ public static bool CanSetIsSparse(
bool? sparse,
bool fromDataAnnotation = false)
=> property.CanSetAnnotation(SqlServerAnnotationNames.Sparse, sparse, fromDataAnnotation);

/// <summary>
/// TODO
/// </summary>
public static PropertyBuilder HasDefaultValue(
this PropertyBuilder propertyBuilder,
object? value,
string defaultConstraintName)
{
propertyBuilder.Metadata.SetDefaultValue(value);
propertyBuilder.Metadata.SetDefaultConstraintName(defaultConstraintName);

return propertyBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static PropertyBuilder<TProperty> HasDefaultValue<TProperty>(
this PropertyBuilder<TProperty> propertyBuilder,
object? value,
string defaultConstraintName)
=> (PropertyBuilder<TProperty>)HasDefaultValue((PropertyBuilder)propertyBuilder, value, defaultConstraintName);

/// <summary>
/// TODO
/// </summary>
public static IConventionPropertyBuilder? HasDefaultValue(
this IConventionPropertyBuilder propertyBuilder,
object? value,
string defaultConstraintName,
bool fromDataAnnotation = false)
{
if (!propertyBuilder.CanSetDefaultValue(value, defaultConstraintName, fromDataAnnotation))
{
return null;
}

propertyBuilder.Metadata.SetDefaultValue(value, fromDataAnnotation);
return propertyBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static bool CanSetDefaultValue(
this IConventionPropertyBuilder propertyBuilder,
object? value,
string defaultConstraintName,
bool fromDataAnnotation = false)
=> propertyBuilder.CanSetAnnotation(
RelationalAnnotationNames.DefaultValue,
value,
fromDataAnnotation)
&& propertyBuilder.CanSetAnnotation(
SqlServerAnnotationNames.DefaultConstraintName,
defaultConstraintName,
fromDataAnnotation);

/// <summary>
/// TODO
/// </summary>
public static PropertyBuilder HasDefaultValueSql(
this PropertyBuilder propertyBuilder,
string? sql,
string defaultConstraintName)
{
propertyBuilder.Metadata.SetDefaultValueSql(sql);
propertyBuilder.Metadata.SetDefaultConstraintName(defaultConstraintName);

return propertyBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static PropertyBuilder<TProperty> HasDefaultValueSql<TProperty>(
this PropertyBuilder<TProperty> propertyBuilder,
string? sql,
string defaultConstraintName)
=> (PropertyBuilder<TProperty>)HasDefaultValueSql((PropertyBuilder)propertyBuilder, sql, defaultConstraintName);

/// <summary>
/// TODO
/// </summary>
public static IConventionPropertyBuilder? HasDefaultValueSql(
this IConventionPropertyBuilder propertyBuilder,
string? sql,
string defaultConstraintName,
bool fromDataAnnotation = false)
{
if (!propertyBuilder.CanSetDefaultValueSql(sql, defaultConstraintName, fromDataAnnotation))
{
return null;
}

propertyBuilder.Metadata.SetDefaultValueSql(sql, fromDataAnnotation);
return propertyBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static bool CanSetDefaultValueSql(
this IConventionPropertyBuilder propertyBuilder,
string? sql,
string defaultConstraintName,
bool fromDataAnnotation = false)
=> propertyBuilder.CanSetAnnotation(
RelationalAnnotationNames.DefaultValueSql,
sql,
fromDataAnnotation)
&& propertyBuilder.CanSetAnnotation(
SqlServerAnnotationNames.DefaultConstraintName,
defaultConstraintName,
fromDataAnnotation);
}
46 changes: 46 additions & 0 deletions src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,4 +1054,50 @@ public static void SetIsSparse(this IMutableProperty property, bool? sparse)
/// <returns>The <see cref="ConfigurationSource" /> for whether the property's column is sparse.</returns>
public static ConfigurationSource? GetIsSparseConfigurationSource(this IConventionProperty property)
=> property.FindAnnotation(SqlServerAnnotationNames.Sparse)?.GetConfigurationSource();

/// <summary>
/// TODO
/// </summary>
public static string? DefaultConstraintName(this IReadOnlyProperty property)
=> (property is RuntimeProperty)
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
: (string?)property[SqlServerAnnotationNames.DefaultConstraintName];

/// <summary>
/// TODO
/// </summary>
public static string DefaultDefaultConstraintName(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
{
var candidate = $"DF_{storeObject.Name}_{property.GetColumnName(storeObject)}";

return candidate.Length > 120 ? candidate[..120] : candidate;
}

/// <summary>
/// TODO
/// </summary>
public static void SetDefaultConstraintName(this IMutableProperty property, string? defaultConstraintName)
=> property.SetAnnotation(SqlServerAnnotationNames.DefaultConstraintName, defaultConstraintName);

/// <summary>
/// TODO
/// </summary>
public static string? SetDefaultConstraintName(
this IConventionProperty property,
string? defaultConstraintName,
bool fromDataAnnotation = false)
{
property.SetAnnotation(
SqlServerAnnotationNames.DefaultConstraintName,
defaultConstraintName,
fromDataAnnotation);

return defaultConstraintName;
}

/// <summary>
/// TODO
/// </summary>
public static ConfigurationSource? GetDefaultConstraintNameConfigurationSource(this IConventionProperty property)
=> property.FindAnnotation(SqlServerAnnotationNames.DefaultConstraintName)?.GetConfigurationSource();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

// ReSharper disable once CheckNamespace

using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Conventions;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions;

/// <summary>
Expand Down Expand Up @@ -72,6 +74,12 @@ public override ConventionSet CreateConventionSet()
conventionSet.SkipNavigationForeignKeyChangedConventions.Add(sqlServerTemporalConvention);
conventionSet.ModelFinalizingConventions.Add(sqlServerTemporalConvention);

var sqlServerDefaultValueConvention = new SqlServerDefaultValueConvention(Dependencies, RelationalDependencies);
ConventionSet.AddAfter(
conventionSet.ModelFinalizingConventions,
sqlServerDefaultValueConvention,
typeof(SqlServerSharedTableConvention));

return conventionSet;
}

Expand Down
Loading