MS SQL Server with EF Core 'Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths' with Delete Behavior SetNull

0

I really thought I'd understood the EF Core delete behavior constraints concerning MS SQL Server, but obviously I don't :-(

Introducing a foreign key with delete behavior "set null" leads to the following exception when updating the database:

ALTER TABLE [AppointmentParticipations] ADD CONSTRAINT [FK_AppointmentParticipations_SelectValueMappings_ResultId] FOREIGN KEY ([ResultId]) REFERENCES [SelectValueMappings] ([Id]) ON DELETE SET NULL; | url: | action: Failed executing DbCommand (17ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] ALTER TABLE [AppointmentParticipations] ADD CONSTRAINT [FK_AppointmentParticipations_SelectValueMappings_ResultId] FOREIGN KEY ([ResultId]) REFERENCES [SelectValueMappings] ([Id]) ON DELETE SET NULL; Microsoft.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_AppointmentParticipations_SelectValueMappings_ResultId' on table 'AppointmentParticipations' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint or index. See previous errors. at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite) at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName) at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery() at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject) at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) ClientConnectionId:40c35c1b-5be2-4cdc-957d-2e9ade19aceb Error Number:1785,State:0,Class:16 Introducing FOREIGN KEY constraint 'FK_AppointmentParticipations_SelectValueMappings_ResultId' on table 'AppointmentParticipations' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint or index. See previous errors.

The concerned class:

public class AppointmentParticipation : BaseEntity
{
    public Guid PersonId { get; private set; }
    public virtual Person Person { get; private set; }
    public Guid AppointmentId { get; private set; }
    public virtual Appointment Appointment { get; private set; }
    public Guid? ResultId { get; private set; }
    public virtual SelectValueMapping Result { get; private set; }
    public Guid? PredictionId { get; private set; }
    public virtual SelectValueMapping Prediction { get; private set; }
}

The entity type configuration:

 public class AppointmentParticipationConfiguration : IEntityTypeConfiguration<AppointmentParticipation>
   {
        public void Configure(EntityTypeBuilder<AppointmentParticipation> builder)
        {
            builder
                .HasOne(e => e.Person)
                .WithMany(p => p.AppointmentParticipations)
                .HasForeignKey(e => e.PersonId)
                .OnDelete(DeleteBehavior.Cascade);

            builder
                .HasOne(e => e.Appointment)
                .WithMany(a => a.AppointmentParticipations)
                .HasForeignKey(e => e.AppointmentId)
                .OnDelete(DeleteBehavior.Cascade);

            builder
                .HasOne(e => e.Result)
                .WithMany(c => c.AppointmentParticipationsAsResult)
                .HasForeignKey(e => e.ResultId)
                .OnDelete(DeleteBehavior.SetNull);

            builder
                .HasOne(e => e.Prediction)
                .WithMany(c => c.AppointmentParticipationsAsPrediction)
                .HasForeignKey(e => e.PredictionId)
                .OnDelete(DeleteBehavior.SetNull);
        }
    }

Why may setting a foreign key to null cause cycles or multiple cascade paths? I thought that this can only be the case with delete behavior cascade? I'm really confused :-(

c#
sql-server
entity-framework-core
ef-core-3.1
asked on Stack Overflow Mar 14, 2020 by MatterOfFact • edited Mar 14, 2020 by MatterOfFact

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0