Skip to content

Commit

Permalink
Add metadata for configuring required dependents
Browse files Browse the repository at this point in the history
Part of #12100
  • Loading branch information
AndriySvyryd committed Aug 3, 2020
1 parent 58ad871 commit da1ae86
Show file tree
Hide file tree
Showing 43 changed files with 1,137 additions and 450 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1913,7 +1913,8 @@ protected virtual Dictionary<IEntityType, List<ITable>> DiffData(

foreach (var targetProperty in entry.EntityType.GetProperties())
{
if (!(targetProperty.ValueGenerated == ValueGenerated.Never || targetProperty.ValueGenerated == ValueGenerated.OnAdd))
if (targetProperty.ValueGenerated != ValueGenerated.Never
&& targetProperty.ValueGenerated != ValueGenerated.OnAdd)
{
continue;
}
Expand Down
26 changes: 22 additions & 4 deletions src/EFCore/Diagnostics/CoreEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ private enum Id
ShadowPropertyCreated = CoreBaseId + 600,
RedundantIndexRemoved,
IncompatibleMatchingForeignKeyProperties,
RequiredAttributeOnDependent,
RequiredAttributeOnBothNavigations,
RequiredAttributeOnDependent, // Unused
RequiredAttributeOnBothNavigations, // Unused
ConflictingShadowForeignKeysWarning,
MultiplePrimaryKeyCandidates,
MultipleNavigationProperties,
Expand All @@ -99,13 +99,14 @@ private enum Id
ConflictingForeignKeyAttributesOnNavigationAndPropertyWarning,
RedundantForeignKeyWarning,
NonNullableInverted, // Unused
NonNullableReferenceOnBothNavigations,
NonNullableReferenceOnDependent,
NonNullableReferenceOnBothNavigations, // Unused
NonNullableReferenceOnDependent, // Unused
RequiredAttributeInverted, // Unused
RequiredAttributeOnCollection,
CollectionWithoutComparer,
ConflictingKeylessAndKeyAttributesWarning,
PossibleIncorrectRequiredNavigationWithQueryFilterInteractionWarning,
RequiredAttributeOnSkipNavigation,

// ChangeTracking events
DetectChangesStarting = CoreBaseId + 800,
Expand Down Expand Up @@ -435,6 +436,7 @@ public static readonly EventId InvalidIncludePathError
/// This event uses the <see cref="TwoPropertyBaseCollectionsEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </summary>
[Obsolete]
public static readonly EventId RequiredAttributeOnBothNavigations = MakeModelId(Id.RequiredAttributeOnBothNavigations);

/// <summary>
Expand All @@ -448,6 +450,7 @@ public static readonly EventId InvalidIncludePathError
/// This event uses the <see cref="TwoPropertyBaseCollectionsEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </summary>
[Obsolete]
public static readonly EventId NonNullableReferenceOnBothNavigations = MakeModelId(Id.NonNullableReferenceOnBothNavigations);

/// <summary>
Expand All @@ -461,6 +464,7 @@ public static readonly EventId InvalidIncludePathError
/// This event uses the <see cref="NavigationEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </summary>
[Obsolete]
public static readonly EventId RequiredAttributeOnDependent = MakeModelId(Id.RequiredAttributeOnDependent);

/// <summary>
Expand All @@ -474,6 +478,7 @@ public static readonly EventId InvalidIncludePathError
/// This event uses the <see cref="NavigationEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </summary>
[Obsolete]
public static readonly EventId NonNullableReferenceOnDependent = MakeModelId(Id.NonNullableReferenceOnDependent);

/// <summary>
Expand All @@ -489,6 +494,19 @@ public static readonly EventId InvalidIncludePathError
/// </summary>
public static readonly EventId RequiredAttributeOnCollection = MakeModelId(Id.RequiredAttributeOnCollection);

/// <summary>
/// <para>
/// The <see cref="RequiredAttribute" /> on the skip navigation property was ignored.
/// </para>
/// <para>
/// This event is in the <see cref="DbLoggerCategory.Model" /> category.
/// </para>
/// <para>
/// This event uses the <see cref="SkipNavigationEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </summary>
public static readonly EventId RequiredAttributeOnSkipNavigation = MakeModelId(Id.RequiredAttributeOnSkipNavigation);

/// <summary>
/// <para>
/// The properties that best match the foreign key convention are already used by a different foreign key.
Expand Down
44 changes: 44 additions & 0 deletions src/EFCore/Diagnostics/CoreLoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,7 @@ public static void RequiredAttributeInverted(
}
}

[Obsolete]
private static string RequiredAttributeInverted(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string>)definition;
Expand Down Expand Up @@ -1319,6 +1320,7 @@ public static void NonNullableInverted(
}
}

[Obsolete]
private static string NonNullableInverted(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string>)definition;
Expand All @@ -1332,6 +1334,7 @@ private static string NonNullableInverted(EventDefinitionBase definition, EventD
/// <param name="diagnostics"> The diagnostics logger to use. </param>
/// <param name="firstNavigation"> The first navigation property. </param>
/// <param name="secondNavigation"> The second navigation property. </param>
[Obsolete]
public static void RequiredAttributeOnBothNavigations(
[NotNull] this IDiagnosticsLogger<DbLoggerCategory.Model> diagnostics,
[NotNull] INavigation firstNavigation,
Expand Down Expand Up @@ -1361,6 +1364,7 @@ public static void RequiredAttributeOnBothNavigations(
}
}

[Obsolete]
private static string RequiredAttributeOnBothNavigations(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string, string, string>)definition;
Expand All @@ -1380,6 +1384,7 @@ private static string RequiredAttributeOnBothNavigations(EventDefinitionBase def
/// <param name="diagnostics"> The diagnostics logger to use. </param>
/// <param name="firstNavigation"> The first navigation property. </param>
/// <param name="secondNavigation"> The second navigation property. </param>
[Obsolete]
public static void NonNullableReferenceOnBothNavigations(
[NotNull] this IDiagnosticsLogger<DbLoggerCategory.Model> diagnostics,
[NotNull] INavigation firstNavigation,
Expand Down Expand Up @@ -1409,6 +1414,7 @@ public static void NonNullableReferenceOnBothNavigations(
}
}

[Obsolete]
private static string NonNullableReferenceOnBothNavigations(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string, string, string>)definition;
Expand All @@ -1427,6 +1433,7 @@ private static string NonNullableReferenceOnBothNavigations(EventDefinitionBase
/// </summary>
/// <param name="diagnostics"> The diagnostics logger to use. </param>
/// <param name="navigation"> The navigation property. </param>
[Obsolete]
public static void RequiredAttributeOnDependent(
[NotNull] this IDiagnosticsLogger<DbLoggerCategory.Model> diagnostics,
[NotNull] INavigation navigation)
Expand All @@ -1451,6 +1458,7 @@ public static void RequiredAttributeOnDependent(
}
}

[Obsolete]
private static string RequiredAttributeOnDependent(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string>)definition;
Expand All @@ -1463,6 +1471,7 @@ private static string RequiredAttributeOnDependent(EventDefinitionBase definitio
/// </summary>
/// <param name="diagnostics"> The diagnostics logger to use. </param>
/// <param name="navigation"> The navigation property. </param>
[Obsolete]
public static void NonNullableReferenceOnDependent(
[NotNull] this IDiagnosticsLogger<DbLoggerCategory.Model> diagnostics,
[NotNull] INavigation navigation)
Expand All @@ -1488,6 +1497,7 @@ public static void NonNullableReferenceOnDependent(
}
}

[Obsolete]
private static string NonNullableReferenceOnDependent(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string>)definition;
Expand Down Expand Up @@ -1529,6 +1539,40 @@ private static string RequiredAttributeOnCollection(EventDefinitionBase definiti
return d.GenerateMessage(p.Navigation.DeclaringEntityType.DisplayName(), p.Navigation.Name);
}

/// <summary>
/// Logs for the <see cref="CoreEventId.RequiredAttributeOnSkipNavigation" /> event.
/// </summary>
/// <param name="diagnostics"> The diagnostics logger to use. </param>
/// <param name="navigation"> The navigation property. </param>
public static void RequiredAttributeOnSkipNavigation(
[NotNull] this IDiagnosticsLogger<DbLoggerCategory.Model> diagnostics,
[NotNull] ISkipNavigation navigation)
{
var definition = CoreResources.LogRequiredAttributeOnSkipNavigation(diagnostics);

if (diagnostics.ShouldLog(definition))
{
definition.Log(diagnostics, navigation.DeclaringEntityType.DisplayName(), navigation.Name);
}

if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
{
var eventData = new SkipNavigationEventData(
definition,
RequiredAttributeOnSkipNavigation,
navigation);

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

private static string RequiredAttributeOnSkipNavigation(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string>)definition;
var p = (SkipNavigationEventData)payload;
return d.GenerateMessage(p.Navigation.DeclaringEntityType.DisplayName(), p.Navigation.Name);
}

/// <summary>
/// Logs for the <see cref="CoreEventId.ConflictingShadowForeignKeysWarning" /> event.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/EFCore/Diagnostics/LoggingDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ public abstract class LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
[Obsolete]
public EventDefinitionBase LogRequiredAttributeOnDependent;

/// <summary>
Expand All @@ -530,6 +531,7 @@ public abstract class LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
[Obsolete]
public EventDefinitionBase LogNonNullableReferenceOnDependent;

/// <summary>
Expand All @@ -539,6 +541,7 @@ public abstract class LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
[Obsolete]
public EventDefinitionBase LogRequiredAttributeOnBothNavigations;

/// <summary>
Expand All @@ -548,6 +551,7 @@ public abstract class LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
[Obsolete]
public EventDefinitionBase LogNonNullableReferenceOnBothNavigations;

/// <summary>
Expand All @@ -568,6 +572,15 @@ public abstract class LoggingDefinitions
[EntityFrameworkInternal]
public EventDefinitionBase LogRequiredAttributeOnCollection;

/// <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 LogRequiredAttributeOnSkipNavigation;

/// <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
Expand Down
3 changes: 1 addition & 2 deletions src/EFCore/Infrastructure/CoreOptionsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ private WarningsConfiguration _warningsConfiguration
.TryWithExplicit(CoreEventId.ManyServiceProvidersCreatedWarning, WarningBehavior.Throw)
.TryWithExplicit(CoreEventId.LazyLoadOnDisposedContextWarning, WarningBehavior.Throw)
.TryWithExplicit(CoreEventId.DetachedLazyLoadingWarning, WarningBehavior.Throw)
.TryWithExplicit(CoreEventId.InvalidIncludePathError, WarningBehavior.Throw)
.TryWithExplicit(CoreEventId.RequiredAttributeOnDependent, WarningBehavior.Throw);
.TryWithExplicit(CoreEventId.InvalidIncludePathError, WarningBehavior.Throw);

/// <summary>
/// Creates a new set of options with everything set to default values.
Expand Down
31 changes: 29 additions & 2 deletions src/EFCore/Metadata/Builders/IConventionForeignKeyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ bool CanSetNavigations(
bool fromDataAnnotation = false);

/// <summary>
/// Configures whether this is a required relationship (i.e. whether none the foreign key properties can
/// Configures whether this is a required relationship (i.e. whether none of the foreign key properties can
/// be assigned <see langword="null" />).
/// </summary>
/// <param name="required">
Expand All @@ -313,7 +313,7 @@ bool CanSetNavigations(
IConventionForeignKeyBuilder IsRequired(bool? required, bool fromDataAnnotation = false);

/// <summary>
/// Returns a value indicating whether this relationship requiredness can be configured
/// Returns a value indicating whether the relationship requiredness can be configured
/// from the current configuration source.
/// </summary>
/// <param name="required">
Expand All @@ -324,6 +324,33 @@ bool CanSetNavigations(
/// <returns> <see langword="true" /> if the relationship requiredness can be configured. </returns>
bool CanSetIsRequired(bool? required, bool fromDataAnnotation = false);

/// <summary>
/// Configures whether the dependent end is required (i.e. whether the principal to dependent navigation can
/// be assigned <see langword="null" />).
/// </summary>
/// <param name="required">
/// A value indicating whether the dependent end is required.
/// <see langword="null" /> to reset to default.
/// </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the dependent end requiredness was configured,
/// <see langword="null" /> otherwise.
/// </returns>
IConventionForeignKeyBuilder IsRequiredDependent(bool? required, bool fromDataAnnotation = false);

/// <summary>
/// Returns a value indicating whether the dependent end requiredness can be configured
/// from the current configuration source.
/// </summary>
/// <param name="required">
/// A value indicating whether this is a required relationship.
/// <see langword="null" /> to reset to default.
/// </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if the relationship requiredness can be configured. </returns>
bool CanSetIsRequiredDependent(bool? required, bool fromDataAnnotation = false);

/// <summary>
/// Configures whether this relationship defines an ownership
/// (i.e. whether the dependent entity must always be accessed via the navigation from the principal entity).
Expand Down
22 changes: 22 additions & 0 deletions src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,27 @@ public interface IConventionNavigationBuilder : IConventionPropertyBaseBuilder
/// <see langword="null" /> otherwise.
/// </returns>
IConventionNavigationBuilder AutoInclude(bool? autoInclude, bool fromDataAnnotation = false);

/// <summary>
/// Returns a value indicating whether this navigation requiredness can be configured
/// from the current configuration source.
/// </summary>
/// <param name="required"> A value indicating whether the navigation should be required. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if requiredness can be set for this navigation. </returns>
bool CanSetIsRequired(bool? required, bool fromDataAnnotation = false);

/// <summary>
/// Configures whether this navigation is required.
/// </summary>
/// <param name="required">
/// A value indicating whether this is a required navigation.
/// <see langword="null" /> to reset to default.
/// </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the requiredness was configured, <see langword="null" /> otherwise.
/// </returns>
IConventionNavigationBuilder IsRequired(bool? required, bool fromDataAnnotation = false);
}
}
Loading

0 comments on commit da1ae86

Please sign in to comment.