Skip to content

Commit

Permalink
Add TPC support for migrations
Browse files Browse the repository at this point in the history
Part of #3170
  • Loading branch information
AndriySvyryd authored Mar 23, 2022
1 parent 5df9bcf commit 75bfaa7
Show file tree
Hide file tree
Showing 19 changed files with 1,557 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2135,6 +2135,7 @@ protected virtual void Annotations(
foreach (var annotation in annotations)
{
// TODO: Give providers an opportunity to render these as provider-specific extension methods
// Issue #6546
builder
.AppendLine()
.Append(".Annotation(")
Expand All @@ -2157,6 +2158,7 @@ protected virtual void OldAnnotations(
foreach (var annotation in annotations)
{
// TODO: Give providers an opportunity to render these as provider-specific extension methods
// Issue #6546
builder
.AppendLine()
.Append(".OldAnnotation(")
Expand Down
32 changes: 22 additions & 10 deletions src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -675,19 +675,32 @@ protected virtual void GenerateEntityTypeAnnotations(
IEntityType entityType,
IndentedStringBuilder stringBuilder)
{
var annotationList = entityType.GetAnnotations().ToList();
IAnnotation? discriminatorPropertyAnnotation = null;
IAnnotation? discriminatorValueAnnotation = null;
IAnnotation? discriminatorMappingCompleteAnnotation = null;

var discriminatorPropertyAnnotation = annotationList.FirstOrDefault(a => a.Name == CoreAnnotationNames.DiscriminatorProperty);
var discriminatorMappingCompleteAnnotation =
annotationList.FirstOrDefault(a => a.Name == CoreAnnotationNames.DiscriminatorMappingComplete);
var discriminatorValueAnnotation = annotationList.FirstOrDefault(a => a.Name == CoreAnnotationNames.DiscriminatorValue);
foreach (var annotation in entityType.GetAnnotations())
{
switch (annotation.Name)
{
case CoreAnnotationNames.DiscriminatorProperty:
discriminatorPropertyAnnotation = annotation;
break;
case CoreAnnotationNames.DiscriminatorValue:
discriminatorValueAnnotation = annotation;
break;
case CoreAnnotationNames.DiscriminatorMappingComplete:
discriminatorMappingCompleteAnnotation = annotation;
break;
}
}

var annotations = Dependencies.AnnotationCodeGenerator
.FilterIgnoredAnnotations(entityType.GetAnnotations())
.ToDictionary(a => a.Name, a => a);

var tableNameAnnotation = annotations.Find(RelationalAnnotationNames.TableName);
if (tableNameAnnotation?.Value != null
if (tableNameAnnotation != null
|| entityType.BaseType == null)
{
var tableName = (string?)tableNameAnnotation?.Value ?? entityType.GetTableName();
Expand Down Expand Up @@ -773,7 +786,7 @@ protected virtual void GenerateEntityTypeAnnotations(
annotations.Remove(RelationalAnnotationNames.Schema);

var viewNameAnnotation = annotations.Find(RelationalAnnotationNames.ViewName);
if (viewNameAnnotation?.Value != null
if (viewNameAnnotation != null
|| entityType.BaseType == null)
{
var viewName = (string?)viewNameAnnotation?.Value ?? entityType.GetViewName();
Expand All @@ -796,7 +809,6 @@ protected virtual void GenerateEntityTypeAnnotations(
stringBuilder
.Append(", ")
.Append(Code.Literal((string)viewSchemaAnnotation.Value));
annotations.Remove(viewSchemaAnnotation.Name);
}

stringBuilder.AppendLine(");");
Expand All @@ -807,7 +819,7 @@ protected virtual void GenerateEntityTypeAnnotations(
annotations.Remove(RelationalAnnotationNames.ViewDefinitionSql);

var functionNameAnnotation = annotations.Find(RelationalAnnotationNames.FunctionName);
if (functionNameAnnotation?.Value != null
if (functionNameAnnotation != null
|| entityType.BaseType == null)
{
var functionName = (string?)functionNameAnnotation?.Value ?? entityType.GetFunctionName();
Expand All @@ -828,7 +840,7 @@ protected virtual void GenerateEntityTypeAnnotations(
}

var sqlQueryAnnotation = annotations.Find(RelationalAnnotationNames.SqlQuery);
if (sqlQueryAnnotation?.Value != null
if (sqlQueryAnnotation != null
|| entityType.BaseType == null)
{
var sqlQuery = (string?)sqlQueryAnnotation?.Value ?? entityType.GetSqlQuery();
Expand Down
34 changes: 34 additions & 0 deletions src/EFCore.Relational/Design/AnnotationCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ private static readonly MethodInfo EntityTypeHasCommentMethodInfo
= typeof(RelationalEntityTypeBuilderExtensions).GetRuntimeMethod(
nameof(RelationalEntityTypeBuilderExtensions.HasComment), new[] { typeof(EntityTypeBuilder), typeof(string) })!;

private static readonly MethodInfo EntityTypeUseTpcMappingStrategyMethodInfo
= typeof(RelationalEntityTypeBuilderExtensions).GetRuntimeMethod(
nameof(RelationalEntityTypeBuilderExtensions.UseTpcMappingStrategy), new[] { typeof(EntityTypeBuilder) })!;

private static readonly MethodInfo EntityTypeUseTphMappingStrategyMethodInfo
= typeof(RelationalEntityTypeBuilderExtensions).GetRuntimeMethod(
nameof(RelationalEntityTypeBuilderExtensions.UseTphMappingStrategy), new[] { typeof(EntityTypeBuilder) })!;

private static readonly MethodInfo EntityTypeUseTptMappingStrategyMethodInfo
= typeof(RelationalEntityTypeBuilderExtensions).GetRuntimeMethod(
nameof(RelationalEntityTypeBuilderExtensions.UseTptMappingStrategy), new[] { typeof(EntityTypeBuilder) })!;

private static readonly MethodInfo PropertyHasColumnNameMethodInfo
= typeof(RelationalPropertyBuilderExtensions).GetRuntimeMethod(
nameof(RelationalPropertyBuilderExtensions.HasColumnName), new[] { typeof(PropertyBuilder), typeof(string) })!;
Expand Down Expand Up @@ -204,6 +216,28 @@ public virtual IReadOnlyList<MethodCallCodeFragment> GenerateFluentApiCalls(
annotations,
RelationalAnnotationNames.Comment, EntityTypeHasCommentMethodInfo, methodCallCodeFragments);

if (annotations.TryGetValue(RelationalAnnotationNames.MappingStrategy, out var mappingStrategyAnnotation)
&& mappingStrategyAnnotation.Value is string mappingStrategy)
{
var strategyCall = mappingStrategy switch
{
RelationalAnnotationNames.TpcMappingStrategy => EntityTypeUseTpcMappingStrategyMethodInfo,
RelationalAnnotationNames.TptMappingStrategy => EntityTypeUseTptMappingStrategyMethodInfo,
RelationalAnnotationNames.TphMappingStrategy => EntityTypeUseTphMappingStrategyMethodInfo,
_ => null
};

if (strategyCall != null)
{
if (entityType.BaseType == null)
{
methodCallCodeFragments.Add(new MethodCallCodeFragment(strategyCall));
}

annotations.Remove(mappingStrategyAnnotation.Name);
}
}

methodCallCodeFragments.AddRange(GenerateFluentApiCallsHelper(entityType, annotations, GenerateFluentApi));

return methodCallCodeFragments;
Expand Down
6 changes: 3 additions & 3 deletions src/EFCore.Relational/Diagnostics/RelationalEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private enum Id
ForeignKeyPropertiesMappedToUnrelatedTables,
OptionalDependentWithoutIdentifyingPropertyWarning,
DuplicateColumnOrders,
ForeignKeyTPCPrincipalWarning,
ForeignKeyTpcPrincipalWarning,
TpcStoreGeneratedIdentityWarning,

// Update events
Expand Down Expand Up @@ -752,8 +752,8 @@ private static EventId MakeValidationId(Id id)
/// This event uses the <see cref="ForeignKeyEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </remarks>
public static readonly EventId ForeignKeyTPCPrincipalWarning =
MakeValidationId(Id.ForeignKeyTPCPrincipalWarning);
public static readonly EventId ForeignKeyTpcPrincipalWarning =
MakeValidationId(Id.ForeignKeyTpcPrincipalWarning);

/// <summary>
/// The PK is using store-generated values in TPC.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2832,15 +2832,15 @@ private static string ForeignKeyPropertiesMappedToUnrelatedTables(EventDefinitio
}

/// <summary>
/// Logs the <see cref="RelationalEventId.ForeignKeyTPCPrincipalWarning" /> event.
/// Logs the <see cref="RelationalEventId.ForeignKeyTpcPrincipalWarning" /> event.
/// </summary>
/// <param name="diagnostics">The diagnostics logger to use.</param>
/// <param name="foreignKey">The foreign key.</param>
public static void ForeignKeyTPCPrincipalWarning(
public static void ForeignKeyTpcPrincipalWarning(
this IDiagnosticsLogger<DbLoggerCategory.Model.Validation> diagnostics,
IForeignKey foreignKey)
{
var definition = RelationalResources.LogForeignKeyTPCPrincipal(diagnostics);
var definition = RelationalResources.LogForeignKeyTpcPrincipal(diagnostics);

if (diagnostics.ShouldLog(definition))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
public EventDefinitionBase? LogForeignKeyTPCPrincipal;
public EventDefinitionBase? LogForeignKeyTpcPrincipal;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private static FromSqlQueryRootExpression GenerateFromSqlQueryRoot(
if ((entityType.BaseType != null || entityType.GetDirectlyDerivedTypes().Any())
&& entityType.FindDiscriminatorProperty() == null)
{
throw new InvalidOperationException(RelationalStrings.MethodOnNonTPHRootNotSupported(memberName, entityType.DisplayName()));
throw new InvalidOperationException(RelationalStrings.MethodOnNonTphRootNotSupported(memberName, entityType.DisplayName()));
}

return new FromSqlQueryRootExpression(
Expand Down
14 changes: 7 additions & 7 deletions src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ protected virtual void ValidateDbFunctions(
&& entityType.FindDiscriminatorProperty() == null)
{
throw new InvalidOperationException(
RelationalStrings.TableValuedFunctionNonTPH(dbFunction.ModelName, entityType.DisplayName()));
RelationalStrings.TableValuedFunctionNonTph(dbFunction.ModelName, entityType.DisplayName()));
}
}

Expand Down Expand Up @@ -1056,7 +1056,7 @@ protected virtual void ValidateSharedForeignKeysCompatibility(
{
if (foreignKey.PrincipalEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy)
{
logger.ForeignKeyTPCPrincipalWarning(foreignKey);
logger.ForeignKeyTpcPrincipalWarning(foreignKey);
}

var derivedTables = foreignKey.DeclaringEntityType.GetDerivedTypes()
Expand Down Expand Up @@ -1309,7 +1309,7 @@ protected override void ValidateInheritanceMapping(
&& storeObject != null)
{
throw new InvalidOperationException(
RelationalStrings.AbstractTPC(entityType.DisplayName(), storeObject));
RelationalStrings.AbstractTpc(entityType.DisplayName(), storeObject));
}
}

Expand Down Expand Up @@ -1403,9 +1403,9 @@ private static void ValidateNonTPHMapping(IEntityType rootEntityType, bool forTa
{
throw new InvalidOperationException(
forTables
? RelationalStrings.NonTPHTableClash(
? RelationalStrings.NonTphTableClash(
entityType.DisplayName(), otherType.DisplayName(), entityType.GetSchemaQualifiedTableName())
: RelationalStrings.NonTPHViewClash(
: RelationalStrings.NonTphViewClash(
entityType.DisplayName(), otherType.DisplayName(), entityType.GetSchemaQualifiedViewName()));
}

Expand Down Expand Up @@ -1439,10 +1439,10 @@ private static void ValidateTPHMapping(IEntityType rootEntityType, bool forTable
{
throw new InvalidOperationException(
forTables
? RelationalStrings.TPHTableMismatch(
? RelationalStrings.TphTableMismatch(
entityType.DisplayName(), entityType.GetSchemaQualifiedTableName(),
firstType.DisplayName(), firstType.GetSchemaQualifiedTableName())
: RelationalStrings.TPHViewMismatch(
: RelationalStrings.TphViewMismatch(
entityType.DisplayName(), entityType.GetSchemaQualifiedViewName(),
firstType.DisplayName(), firstType.GetSchemaQualifiedViewName()));
}
Expand Down
Loading

0 comments on commit 75bfaa7

Please sign in to comment.