Skip to content
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
15 changes: 15 additions & 0 deletions src/EFCore.Relational/Diagnostics/RelationalEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ private enum Id
TpcStoreGeneratedIdentityWarning,
KeyPropertiesNotMappedToTable,
StoredProcedureConcurrencyTokenNotMapped,
TriggerOnNonRootTphEntity,

// Update events
BatchReadyForExecution = CoreEventId.RelationalBaseId + 700,
Expand Down Expand Up @@ -887,6 +888,20 @@ private static EventId MakeValidationId(Id id)
public static readonly EventId StoredProcedureConcurrencyTokenNotMapped =
MakeValidationId(Id.StoredProcedureConcurrencyTokenNotMapped);

/// <summary>
/// Can't configure a trigger on the non-root entity type in a TPH hierarchy.
/// </summary>
/// <remarks>
/// <para>
/// This event is in the <see cref="DbLoggerCategory.Model.Validation" /> category.
/// </para>
/// <para>
/// This event uses the <see cref="EntityTypeEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </remarks>
public static readonly EventId TriggerOnNonRootTphEntity =
MakeValidationId(Id.TriggerOnNonRootTphEntity);

/// <summary>
/// A foreign key specifies properties which don't map to the related tables.
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,6 +1717,40 @@ public static void TransactionDisposed(
}
}

/// <summary>
/// Logs for the <see cref="RelationalEventId.TransactionError" /> event.
/// </summary>
/// <param name="diagnostics">The diagnostics logger to use.</param>
/// <param name="entityType">The entity type.</param>
public static void TriggerOnNonRootTphEntity(
this IDiagnosticsLogger<DbLoggerCategory.Model.Validation> diagnostics,
IEntityType entityType)
{
var definition = RelationalResources.LogTriggerOnNonRootTphEntity(diagnostics);

if (diagnostics.ShouldLog(definition))
{
definition.Log(diagnostics, entityType.DisplayName(), entityType.GetRootType().DisplayName());
}

if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
{
var eventData = new EntityTypeEventData(
definition,
TriggerOnNonRootTphEntity,
entityType);

diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
}
}

private static string TriggerOnNonRootTphEntity(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string>)definition;
var e = (EntityTypeEventData)payload;
return d.GenerateMessage(e.EntityType.DisplayName(), e.EntityType.GetRootType().DisplayName());
}

/// <summary>
/// Logs for the <see cref="RelationalEventId.TransactionError" /> event.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,4 +681,13 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
/// </summary>
[EntityFrameworkInternal]
public EventDefinitionBase? LogUnexpectedTrailingResultSetWhenSaving;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
public EventDefinitionBase? LogTriggerOnNonRootTphEntity;
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public override void Validate(IModel model, IDiagnosticsLogger<DbLoggerCategory.
ValidateDefaultValuesOnKeys(model, logger);
ValidateBoolsWithDefaults(model, logger);
ValidateIndexProperties(model, logger);
ValidateTriggers(model, logger);
ValidateJsonEntities(model, logger);
}

Expand Down Expand Up @@ -2483,9 +2482,7 @@ protected override void ValidateTriggers(
if (entityType.BaseType is not null
&& entityType.GetMappingStrategy() == RelationalAnnotationNames.TphMappingStrategy)
{
throw new InvalidOperationException(
RelationalStrings.CannotConfigureTriggerNonRootTphEntity(
entityType.DisplayName(), entityType.GetRootType().DisplayName()));
logger.TriggerOnNonRootTphEntity(entityType);
}

var tableName = entityType.GetTableName();
Expand Down
33 changes: 25 additions & 8 deletions src/EFCore.Relational/Properties/RelationalStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/EFCore.Relational/Properties/RelationalStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@
<data name="CannotCompareComplexTypeToNull" xml:space="preserve">
<value>Comparing complex types to null is not supported.</value>
</data>
<data name="CannotConfigureTriggerNonRootTphEntity" xml:space="preserve">
<value>Can't configure a trigger on entity type '{entityType}', which is in a TPH hierarchy and isn't the root. Configure the trigger on the TPH root entity type '{rootEntityType}' instead.</value>
</data>
<data name="CannotProjectNullableComplexType" xml:space="preserve">
<value>You are attempting to project out complex type '{complexType}' via an optional navigation; that is currently not supported. Either project out the complex type in a non-optional context, or project the containing entity type along with the complex type.</value>
</data>
Expand Down Expand Up @@ -846,6 +843,10 @@
<value>An error occurred using a transaction.</value>
<comment>Error RelationalEventId.TransactionError</comment>
</data>
<data name="LogTriggerOnNonRootTphEntity" xml:space="preserve">
<value>Can't configure a trigger on entity type '{entityType}', which is in a TPH hierarchy and isn't the root. Configure the trigger on the TPH root entity type '{rootEntityType}' instead.</value>
<comment>Warning RelationalEventId.TriggerOnNonRootTphEntity string string</comment>
</data>
<data name="LogUnexpectedTrailingResultSetWhenSaving" xml:space="preserve">
<value>An unexpected trailing result set was found when reading the results of a SaveChanges operation; this may indicate that a stored procedure returned a result set without being configured for it in the EF model. Check your stored procedure definitions.</value>
<comment>Warning RelationalEventId.UnexpectedTrailingResultSetWhenSaving</comment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3769,11 +3769,8 @@ public void Detects_trigger_on_TPH_non_root()
modelBuilder.Entity<Animal>();
modelBuilder.Entity<Cat>().ToTable(tb => tb.HasTrigger("SomeTrigger"));

VerifyError(
RelationalStrings.CannotConfigureTriggerNonRootTphEntity(
modelBuilder.Model.FindEntityType(typeof(Cat))!.DisplayName(),
modelBuilder.Model.FindEntityType(typeof(Animal))!.DisplayName()),
modelBuilder);
VerifyWarning(RelationalResources.LogTriggerOnNonRootTphEntity(new TestLogger<TestRelationalLoggingDefinitions>())
.GenerateMessage("Cat", "Animal"), modelBuilder);
}

private class TpcBase
Expand Down