Skip to content

Commit

Permalink
Allow table/column comments to be specified in the model
Browse files Browse the repository at this point in the history
  • Loading branch information
Muppets committed Jun 11, 2019
1 parent b15966f commit b1be679
Show file tree
Hide file tree
Showing 23 changed files with 808 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ protected virtual void Generate([NotNull] AddColumnOperation operation, [NotNull
.Append(Code.UnknownLiteral(operation.DefaultValue));
}

if (operation.Comment != null)
{
builder
.AppendLine(",")
.Append("comment: ")
.Append(Code.Literal(operation.Comment));
}

builder.Append(")");

Annotations(operation.GetAnnotations(), builder);
Expand Down Expand Up @@ -518,6 +526,14 @@ protected virtual void Generate([NotNull] AlterColumnOperation operation, [NotNu
.Append(Code.UnknownLiteral(operation.DefaultValue));
}

if (operation.Comment != null)
{
builder
.AppendLine(",")
.Append("comment: ")
.Append(Code.Literal(operation.Comment));
}

if (operation.OldColumn.ClrType != null)
{
builder.AppendLine(",")
Expand Down Expand Up @@ -589,6 +605,14 @@ protected virtual void Generate([NotNull] AlterColumnOperation operation, [NotNu
.Append(Code.UnknownLiteral(operation.OldColumn.DefaultValue));
}

if (operation.OldColumn.Comment != null)
{
builder
.AppendLine(",")
.Append("oldComment: ")
.Append(Code.Literal(operation.OldColumn.Comment));
}

builder.Append(")");

Annotations(operation.GetAnnotations(), builder);
Expand Down Expand Up @@ -736,6 +760,14 @@ protected virtual void Generate([NotNull] AlterTableOperation operation, [NotNul
.Append(Code.Literal(operation.Schema));
}

if (operation.Comment != null)
{
builder
.AppendLine(",")
.Append("comment: ")
.Append(Code.Literal(operation.Comment));
}

builder.Append(")");

Annotations(operation.GetAnnotations(), builder);
Expand Down Expand Up @@ -1163,7 +1195,17 @@ protected virtual void Generate([NotNull] CreateTableOperation operation, [NotNu
}
}

builder.Append("})");
builder.Append("}");

if (operation.Comment != null)
{
builder
.AppendLine(",")
.Append("comment: ")
.Append(Code.Literal(operation.Comment));
}

builder.Append(")");

Annotations(operation.GetAnnotations(), builder);
}
Expand Down
17 changes: 17 additions & 0 deletions src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ protected virtual void GeneratePropertyAnnotations([NotNull] IProperty property,
GenerateFluentApiForAnnotation(ref annotations, RelationalAnnotationNames.DefaultValueSql, nameof(RelationalPropertyBuilderExtensions.HasDefaultValueSql), stringBuilder);
GenerateFluentApiForAnnotation(ref annotations, RelationalAnnotationNames.ComputedColumnSql, nameof(RelationalPropertyBuilderExtensions.HasComputedColumnSql), stringBuilder);
GenerateFluentApiForAnnotation(ref annotations, RelationalAnnotationNames.IsFixedLength, nameof(RelationalPropertyBuilderExtensions.IsFixedLength), stringBuilder);
GenerateFluentApiForAnnotation(ref annotations, RelationalAnnotationNames.Comment, nameof(RelationalPropertyBuilderExtensions.HasComment), stringBuilder);
GenerateFluentApiForAnnotation(ref annotations, CoreAnnotationNames.MaxLength, nameof(PropertyBuilder.HasMaxLength), stringBuilder);
GenerateFluentApiForAnnotation(ref annotations, CoreAnnotationNames.Unicode, nameof(PropertyBuilder.IsUnicode), stringBuilder);

Expand Down Expand Up @@ -758,6 +759,22 @@ protected virtual void GenerateEntityTypeAnnotations(
annotations.Remove(discriminatorValueAnnotation);
}

var commentAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.Comment);

if (commentAnnotation != null)
{
stringBuilder
.AppendLine()
.Append(builderName)
.Append(".")
.Append(nameof(RelationalPropertyBuilderExtensions.HasComment))
.Append("(")
.Append(Code.UnknownLiteral(commentAnnotation.Value))
.AppendLine(");");

annotations.Remove(commentAnnotation);
}

IgnoreAnnotations(
annotations,
CoreAnnotationNames.NavigationCandidates,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,5 +462,78 @@ public static bool CanSetCheckConstraint(
|| (fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention)
.Overrides(constraint.GetConfigurationSource());
}

/// <summary>
/// Configures a comment to be applied to the table
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="comment"> The comment for the table. </param>
/// <returns> A builder to further configure the entity type. </returns>
public static EntityTypeBuilder HasComment(
[NotNull] this EntityTypeBuilder entityTypeBuilder,
[CanBeNull] string comment)
{
Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));

entityTypeBuilder.Metadata.SetComment(comment);
return entityTypeBuilder;
}

/// <summary>
/// Configures a comment to be applied to the table
/// </summary>
/// <typeparam name="TEntity"> The entity type being configured. </typeparam>
/// <param name="entityTypeBuilder"> The entity type builder. </param>
/// <param name="comment"> The comment for the table. </param>
/// <returns> A builder to further configure the entity type. </returns>
public static EntityTypeBuilder<TEntity> HasComment<TEntity>(
[NotNull] this EntityTypeBuilder<TEntity> entityTypeBuilder,
[CanBeNull] string comment)
where TEntity : class
=> (EntityTypeBuilder<TEntity>)HasComment((EntityTypeBuilder)entityTypeBuilder, comment);

/// <summary>
/// Configures a comment to be applied to the table
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="comment"> The comment for the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <c>null</c> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder HasComment(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
[CanBeNull] string comment,
bool fromDataAnnotation = false)
{
Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));

if (!entityTypeBuilder.CanSetComment(comment, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.SetComment(comment, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether a comment can be set for this entity type
/// from the current configuration source
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="comment"> The comment for the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <c>true</c> if the configuration can be applied. </returns>
public static bool CanSetComment(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
[CanBeNull] string comment,
bool fromDataAnnotation = false)
=> entityTypeBuilder.CanSetAnnotation(
RelationalAnnotationNames.Comment,
comment,
fromDataAnnotation);

}
}
27 changes: 27 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -250,5 +250,32 @@ public static bool RemoveCheckConstraint(
/// <param name="entityType"> The entity type to get the check constraints for. </param>
public static IEnumerable<ICheckConstraint> GetCheckConstraints([NotNull] this IEntityType entityType)
=> CheckConstraint.GetCheckConstraints(entityType);

/// <summary>
/// Returns the comment for the column this property is mapped to.
/// </summary>
/// <param name="entityType"> The entity type. </param>
/// <returns> The comment for the column this property is mapped to. </returns>
public static string GetComment([NotNull] this IEntityType entityType)
=> (string)entityType[RelationalAnnotationNames.Comment];

/// <summary>
/// Configures a comment to be applied to the column this property is mapped to.
/// </summary>
/// <param name="entityType"> The entity type. </param>
/// <param name="comment"> The comment for the column. </param>
public static void SetComment([NotNull] this IMutableEntityType entityType, [CanBeNull] string comment)
=> entityType.SetOrRemoveAnnotation(RelationalAnnotationNames.Comment, comment);

/// <summary>
/// Configures a comment to be applied to the column this property is mapped to.
/// </summary>
/// <param name="entityType"> The entity type. </param>
/// <param name="comment"> The comment for the column. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
public static void SetComment(
[NotNull] this IConventionEntityType entityType, [CanBeNull] string comment, bool fromDataAnnotation = false)
=> entityType.SetOrRemoveAnnotation(RelationalAnnotationNames.Comment, comment, fromDataAnnotation);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -442,5 +442,74 @@ public static bool CanSetDefaultValue(
RelationalAnnotationNames.DefaultValue,
value,
fromDataAnnotation);

/// <summary>
/// Configures a comment to be applied to the column
/// </summary>
/// <param name="propertyBuilder"> The builder for the property being configured. </param>
/// <param name="comment"> The comment for the column. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public static PropertyBuilder HasComment(
[NotNull] this PropertyBuilder propertyBuilder,
[CanBeNull] string comment)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));

propertyBuilder.Metadata.SetComment(comment);

return propertyBuilder;
}

/// <summary>
/// Configures a comment to be applied to the column
/// </summary>
/// <typeparam name="TProperty"> The type of the property being configured. </typeparam>
/// <param name="propertyBuilder"> The builder for the property being configured. </param>
/// <param name="comment"> The comment for the column. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public static PropertyBuilder<TProperty> HasComment<TProperty>(
[NotNull] this PropertyBuilder<TProperty> propertyBuilder,
[CanBeNull] string comment)
=> (PropertyBuilder<TProperty>)HasComment((PropertyBuilder)propertyBuilder, comment);

/// <summary>
/// Configures a comment to be applied to the column
/// </summary>
/// <param name="propertyBuilder"> The builder for the property being configured. </param>
/// <param name="comment"> The comment for the column. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <c>null</c> otherwise.
/// </returns>
public static IConventionPropertyBuilder HasComment(
[NotNull] this IConventionPropertyBuilder propertyBuilder,
[CanBeNull] string comment,
bool fromDataAnnotation = false)
{
if (!propertyBuilder.CanSetComment(comment, fromDataAnnotation))
{
return null;
}

propertyBuilder.Metadata.SetComment(comment, fromDataAnnotation);
return propertyBuilder;
}

/// <summary>
/// Returns a value indicating whether the given value can be set as comment for the column.
/// </summary>
/// <param name="propertyBuilder"> The builder for the property being configured. </param>
/// <param name="comment"> The comment for the column. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <c>true</c> if the given value can be set as default for the column. </returns>
public static bool CanSetComment(
[NotNull] this IConventionPropertyBuilder propertyBuilder,
[CanBeNull] object comment,
bool fromDataAnnotation = false)
=> propertyBuilder.CanSetAnnotation(
RelationalAnnotationNames.Comment,
comment,
fromDataAnnotation);
}
}
41 changes: 41 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -470,5 +470,46 @@ public static IProperty FindSharedTableRootPrimaryKeyProperty([NotNull] this IPr

return principalProperty == property ? null : principalProperty;
}

/// <summary>
/// Returns the comment for the column this property is mapped to.
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> The comment for the column this property is mapped to. </returns>
public static string GetComment([NotNull] this IProperty property)
{
var value = (string)property[RelationalAnnotationNames.Comment];
if (value != null)
{
return value;
}

var sharedTablePrincipalPrimaryKeyProperty = property.FindSharedTableRootPrimaryKeyProperty();
if (sharedTablePrincipalPrimaryKeyProperty != null)
{
return GetComment(sharedTablePrincipalPrimaryKeyProperty);
}

return null;
}

/// <summary>
/// Configures a comment to be applied to the column this property is mapped to.
/// </summary>
/// <param name="property"> The property. </param>
/// <param name="comment"> The comment for the column. </param>
public static void SetComment([NotNull] this IMutableProperty property, [CanBeNull] string comment)
=> property.SetOrRemoveAnnotation(RelationalAnnotationNames.Comment, comment);

/// <summary>
/// Configures a comment to be applied to the column this property is mapped to.
/// </summary>
/// <param name="property"> The property. </param>
/// <param name="comment"> The comment for the column. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
public static void SetComment(
[NotNull] this IConventionProperty property, [CanBeNull] string comment, bool fromDataAnnotation = false)
=> property.SetOrRemoveAnnotation(RelationalAnnotationNames.Comment, comment, fromDataAnnotation);

}
}
29 changes: 29 additions & 0 deletions src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,19 @@ protected virtual void ValidateSharedTableCompatibility(
otherKey.Properties.Format()));
}

var currentComment = entityType.GetComment() ?? "";
var previousComment = nextEntityType.GetComment() ?? "";
if (!currentComment.Equals(previousComment, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
RelationalStrings.IncompatibleTableCommentMismatch(
tableName,
entityType.DisplayName(),
nextEntityType.DisplayName(),
previousComment,
currentComment));
}

typesToValidate.Enqueue(nextEntityType);
}

Expand Down Expand Up @@ -415,6 +428,22 @@ protected virtual void ValidateSharedColumnsCompatibility(
previousDefaultValueSql,
currentDefaultValueSql));
}

var currentComment = property.GetComment() ?? "";
var previousComment = duplicateProperty.GetComment() ?? "";
if (!currentComment.Equals(previousComment, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
RelationalStrings.DuplicateColumnNameCommentMismatch(
duplicateProperty.DeclaringEntityType.DisplayName(),
duplicateProperty.Name,
property.DeclaringEntityType.DisplayName(),
property.Name,
columnName,
tableName,
previousComment,
currentComment));
}
}

if ((missingConcurrencyTokens?.Count ?? 0) != 0)
Expand Down
Loading

0 comments on commit b1be679

Please sign in to comment.