Skip to content

Commit

Permalink
Implement 1:1 relations delete behavior setting and restriction to th…
Browse files Browse the repository at this point in the history
…e dependent side
  • Loading branch information
Vekz committed May 15, 2022
1 parent 5357529 commit 8d9d189
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions;
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-conventions">Model building conventions</see> for more information and examples.
/// </remarks>
public class DeleteBehaviorAttributeConvention : PropertyAttributeConventionBase<DeleteBehaviorAttribute>, INavigationAddedConvention
public class DeleteBehaviorAttributeConvention : PropertyAttributeConventionBase<DeleteBehaviorAttribute>, INavigationAddedConvention, IForeignKeyPrincipalEndChangedConvention, IModelFinalizingConvention
{
/// <summary>
/// Creates a new instance of <see cref="DeleteBehaviorAttributeConvention" />.
Expand Down Expand Up @@ -55,9 +55,74 @@ public void ProcessNavigationAdded(IConventionNavigationBuilder navigationBuilde
}

var foreignKey = navigationBuilder.Metadata.ForeignKey;
if (foreignKey.IsUnique)
{
return;
}

if (foreignKey.GetDeleteBehaviorConfigurationSource() != ConfigurationSource.Explicit)
{
foreignKey.SetDeleteBehavior(navAttribute.Behavior);
}
}

/// <summary>
/// Called after the principal end of a foreign key is changed.
/// </summary>
/// <param name="relationshipBuilder">The builder for the foreign key.</param>
/// <param name="context">Additional information associated with convention execution.</param>
public void ProcessForeignKeyPrincipalEndChanged(IConventionForeignKeyBuilder relationshipBuilder, IConventionContext<IConventionForeignKeyBuilder> context)
{
if (!relationshipBuilder.Metadata.IsUnique)
{
return;
}

var navigation = relationshipBuilder.Metadata.DependentToPrincipal;
if (navigation == null)
{
return;
}

var navAttribute = navigation.PropertyInfo?.GetCustomAttribute<DeleteBehaviorAttribute>();
if (navAttribute == null)
{
return;
}

if (relationshipBuilder.Metadata.GetDeleteBehaviorConfigurationSource() != ConfigurationSource.Explicit)
{
relationshipBuilder.Metadata.SetDeleteBehavior(navAttribute.Behavior);
}
}

/// <summary>
/// Called when a model is being finalized.
/// </summary>
/// <param name="modelBuilder">The builder for the model.</param>
/// <param name="context">Additional information associated with convention execution.</param>
public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
{
foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
{
foreach (var navigation in entityType.GetNavigations())
{
if (!navigation.ForeignKey.IsUnique)
{
return;
}

var navAttribute = navigation.PropertyInfo?.GetCustomAttribute<DeleteBehaviorAttribute>();
if (navAttribute == null)
{
return;
}

if (!navigation.IsOnDependent)
{
throw new InvalidOperationException(CoreStrings.DeleteBehaviorAttributeOnPrincipalProperty);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ public virtual ConventionSet CreateConventionSet()
conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(requiredNavigationAttributeConvention);
conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(nonNullableNavigationConvention);
conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(deleteBehaviorAttributeConvention);

conventionSet.PropertyNullabilityChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

Expand Down Expand Up @@ -242,6 +243,7 @@ public virtual ConventionSet CreateConventionSet()
conventionSet.ModelFinalizingConventions.Add(new QueryFilterRewritingConvention(Dependencies));
conventionSet.ModelFinalizingConventions.Add(inversePropertyAttributeConvention);
conventionSet.ModelFinalizingConventions.Add(backingFieldConvention);
conventionSet.ModelFinalizingConventions.Add(deleteBehaviorAttributeConvention);

conventionSet.ModelFinalizedConventions.Add(new RuntimeModelConvention(Dependencies));

Expand Down

0 comments on commit 8d9d189

Please sign in to comment.