Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sql Server, using OnDelete(DeleteBehavior.SetNull) on parent entity, where child have a trigger should not use OUTPUT #30206

Closed
pajacz opened this issue Feb 3, 2023 · 9 comments

Comments

@pajacz
Copy link

pajacz commented Feb 3, 2023

File a bug

If a parent entity Office has OnDelete(DeleteBehavior.SetNull), with collection of Employee entity, where Employee has a trigger defined. Delete will cause "Error: Cannot continue the execution because the session is in the kill state.", caused by DELETE .. OUTPUT 1 ... instead of SELECT @@rowcount;

Basically issue is, when an entity has SetNull on delete and is linked to an entity with a trigger, you should avoid using OUTPUT. I guess :)

There is a workaround, you have to "set" non existing trigger to Office as well.

modelBuilder.Entity<Office>().ToTable(_ => _.HasTrigger("foo"));

Include your code

class Office {

   public int Id { get; set; } 

  public IEnumerable<Employee> Employees { get; set; } 

}

class Employee {

  public Office Office {get; set;}
  public int? OfficeId {get; set;}

}

Configuration:

modelBuilder.Entity<Office>().HasMany(_ => _.Employees).WithOne(_ => _.Office).OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity<Employee>().ToTable(_ => _.HasTrigger("UpdateSomething"));

test:

var record = context.Find<Office>(1);
context.Remove(record);
context.SaveChanges();

Include stack traces


Microsoft.Data.SqlClient.SqlException: Cannot continue the execution because the session is in the kill state.
  ?, in void SqlConnection.OnError(SqlException exception, bool breakConnection, Action<Action> wrapCloseInAction)
  ?, in void TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, bool callerHasConnectionLock, bool asyncClose)
  ?, in bool TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, out bool dataReady)
  ?, in bool SqlDataReader.TryCloseInternal(bool closeReader)
  ?, in void SqlDataReader.Close()
  ?, in Task DbDataReader.CloseAsync()
  ?, in async ValueTask RelationalDataReader.DisposeAsync() x 2
  ?, in async Task ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
  ?, in async Task ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
  ?, in async Task SqlServerModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
  ?, in async Task<int> BatchExecutor.ExecuteAsync(IEnumerable<ModificationCommandBatch> commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) x 3
  ?, in async Task<int> StateManager.SaveChangesAsync(IList<IUpdateEntry> entriesToSave, CancellationToken cancellationToken) x 2
  ?, in async Task<TResult> SqlServerExecutionStrategy.ExecuteAsync<TState, TResult>(TState state, Func<DbContext, TState, CancellationToken, Task<TResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult<TResult>>> verifySucceeded, C...
  ?, in async Task<int> DbContext.SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken) x 2
  File "SendRepository.cs", line 406, col 5, in async Task<int> SendRepository.SaveAsync(bool bulkMode)
  File "Controllers\Entity\PostDeliveryNoteController.cs", line 61, col 9, in async Task<IActionResult> PostDeliveryNoteController.DeleteAsync(int id)
  ?, in async ValueTask<IActionResult> TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
  ?, in async Task ControllerActionInvoker.InvokeActionMethodAsync()+Awaited(?)
  ?, in async Task ControllerActionInvoker.InvokeNextActionFilterAsync()+Awaited(?)
  ?, in void ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
  ?, in Task ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
  ?, in async Task ControllerActionInvoker.InvokeInnerFilterAsync()+Awaited(?)
  ?, in async Task ResourceInvoker.InvokeFilterPipelineAsync()+Awaited(?)
  ?, in async Task ResourceInvoker.InvokeAsync()+Awaited(?) x 2
  ?, in async Task EndpointMiddleware.Invoke(HttpContext httpContext)+AwaitRequestTask(?)
  ?, in async Task AuthorizationMiddleware.Invoke(HttpContext context)
  ?, in async Task AuthenticationMiddleware.Invoke(HttpContext context)
  ?, in async Task SwaggerUIMiddleware.Invoke(HttpContext httpContext)
  ?, in async Task SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
  ?, in async Task ExceptionHandlerMiddlewareImpl.Invoke(HttpContext context)+Awaited(?)

Include provider and version information

EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 7.0.2, EF 7.0.2
Operating system: MacOS 13.1 (22C65)
IDE: JetBrains Rider 2022.3.1

@pajacz pajacz changed the title Sql Server, using OnDelete(DeleteBehavior.SetNull) parent entity, where child have a trigger should not use OUTPUT Sql Server, using OnDelete(DeleteBehavior.SetNull) on parent entity, where child have a trigger should not use OUTPUT Feb 3, 2023
@ajcvickers
Copy link
Contributor

@roji. This is a variation where a related table to the one being saved has a trigger. This should be covered by #29916, right?

@pajacz
Copy link
Author

pajacz commented Feb 6, 2023

Yes, should be..

@roji
Copy link
Member

roji commented Feb 12, 2023

Yeah...

The above is generally by-design - you have to specify, on a table-by-table basis, whether the OUTPUT clause can be used or not; we don't automatically refrain from using OUTPUT on a dependent just because a principal has been configured as having a trigger. So the "workaround" above of calling HasTrigger on the dependent is the right way to do it (i.e. isn't a workaround).

@ajcvickers
Copy link
Contributor

@roji The point here is that the only entity being saved (Office) doesn't have a trigger in the database. The trigger is on Employee, which is not being saved. But this doesn't work because a cascading update is defined from Office to Employee. So, the workaround, and it is a workaround, is to tell EF that Office has a trigger when it doesn't. Full repro below:

public class Office
{
    public int Id { get; set; }
    public List<Employee> Employees { get; } = new();
}

public class Employee
{
    public int Id { get; set; }
    public Office? Office {get; set;}
    public int? OfficeId {get; set;}
    public int Foo {get; set;}
}

public class Program
{
    public static async Task Main()
    {
        using (var context = new SomeDbContext())
        {
            await context.Database.EnsureDeletedAsync();
            await context.Database.EnsureCreatedAsync();

            await context.Database.ExecuteSqlRawAsync(
                @"
CREATE TRIGGER TRG_InsertUpdateBlog
ON Employee
AFTER INSERT, UPDATE AS
BEGIN
	IF @@ROWCOUNT = 0
		return
	SET nocount on;

    UPDATE Employee set Foo = Foo + 1
    WHERE Id IN(SELECT INSERTED.Id FROM INSERTED);
END");

            context.Add(new Office { Employees = { new() } });

            await context.SaveChangesAsync();
        }

        using (var context = new SomeDbContext())
        {
            var record = context.Find<Office>(1)!;
            context.Remove(record);
            await context.SaveChangesAsync();
        }
    }
}

public class SomeDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Office>()
            .HasMany(_ => _.Employees)
            .WithOne(_ => _.Office)
            .OnDelete(DeleteBehavior.SetNull);

        modelBuilder.Entity<Employee>()
            .ToTable(_ => _.HasTrigger("UpdateSomething"));
    }
}

Output:

warn: 2/12/2023 19:05:58.646 CoreEventId.SensitiveDataLoggingEnabledWarning[10400] (Microsoft.EntityFrameworkCore.Infrastructure)
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
info: 2/12/2023 19:05:59.339 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (33ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
info: 2/12/2023 19:05:59.392 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='60']
      IF SERVERPROPERTY('EngineEdition') <> 5
      BEGIN
          ALTER DATABASE [AllTogetherNow] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
      END;
info: 2/12/2023 19:05:59.404 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (12ms) [Parameters=[], CommandType='Text', CommandTimeout='60']
      DROP DATABASE [AllTogetherNow];
info: 2/12/2023 19:05:59.613 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (178ms) [Parameters=[], CommandType='Text', CommandTimeout='60']
      CREATE DATABASE [AllTogetherNow];
info: 2/12/2023 19:05:59.646 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (33ms) [Parameters=[], CommandType='Text', CommandTimeout='60']
      IF SERVERPROPERTY('EngineEdition') <> 5
      BEGIN
          ALTER DATABASE [AllTogetherNow] SET READ_COMMITTED_SNAPSHOT ON;
      END;
info: 2/12/2023 19:05:59.652 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
info: 2/12/2023 19:05:59.739 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE [Office] (
          [Id] int NOT NULL IDENTITY,
          CONSTRAINT [PK_Office] PRIMARY KEY ([Id])
      );
info: 2/12/2023 19:05:59.741 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE [Employee] (
          [Id] int NOT NULL IDENTITY,
          [OfficeId] int NULL,
          [Foo] int NOT NULL,
          CONSTRAINT [PK_Employee] PRIMARY KEY ([Id]),
          CONSTRAINT [FK_Employee_Office_OfficeId] FOREIGN KEY ([OfficeId]) REFERENCES [Office] ([Id]) ON DELETE SET NULL
      );
info: 2/12/2023 19:05:59.743 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE INDEX [IX_Employee_OfficeId] ON [Employee] ([OfficeId]);
info: 2/12/2023 19:05:59.756 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

      CREATE TRIGGER TRG_InsertUpdateBlog
      ON Employee
      AFTER INSERT, UPDATE AS
      BEGIN
        IF @@ROWCOUNT = 0
                return
        SET nocount on;

          UPDATE Employee set Foo = Foo + 1
          WHERE Id IN(SELECT INSERTED.Id FROM INSERTED);
      END
info: 2/12/2023 19:05:59.960 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (14ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SET IMPLICIT_TRANSACTIONS OFF;
      SET NOCOUNT ON;
      INSERT INTO [Office]
      OUTPUT INSERTED.[Id]
      DEFAULT VALUES;
info: 2/12/2023 19:06:00.056 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (48ms) [Parameters=[@p0='0', @p1='1' (Nullable = true)], CommandType='Text', CommandTimeout='30']
      SET NOCOUNT ON;
      INSERT INTO [Employee] ([Foo], [OfficeId])
      VALUES (@p0, @p1);
      SELECT [Id]
      FROM [Employee]
      WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
info: 2/12/2023 19:06:00.347 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (2ms) [Parameters=[@__p_0='1'], CommandType='Text', CommandTimeout='30']
      SELECT TOP(1) [o].[Id]
      FROM [Office] AS [o]
      WHERE [o].[Id] = @__p_0
info: 2/12/2023 19:06:00.400 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (39ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
      SET IMPLICIT_TRANSACTIONS OFF;
      SET NOCOUNT ON;
      DELETE FROM [Office]
      OUTPUT 1
      WHERE [Id] = @p0;
fail: 2/12/2023 19:06:00.426 CoreEventId.SaveChangesFailed[10000] (Microsoft.EntityFrameworkCore.Update)
      An exception occurred in the database while saving changes for context type 'SomeDbContext'.
      Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot continue the execution because the session is in the kill state.
      A severe error occurred on the current command.  The results, if any, should be discarded.
         at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 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.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
         at Microsoft.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
         at Microsoft.Data.SqlClient.SqlDataReader.ReadAsyncExecute(Task task, Object state)
         at Microsoft.Data.SqlClient.SqlDataReader.InvokeAsyncCall[T](SqlDataReaderBaseAsyncCallContext`1 context)
      --- End of stack trace from previous location ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithRowsAffectedOnlyAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
      ClientConnectionId:1fcfd71b-b424-4a36-b4f1-894256d4e78f
      Error Number:596,State:1,Class:21
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.SqlServer.Update.Internal.SqlServerModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
Unhandled exception. Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot continue the execution because the session is in the kill state.
A severe error occurred on the current command.  The results, if any, should be discarded.
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 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.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
   at Microsoft.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
   at Microsoft.Data.SqlClient.SqlDataReader.ReadAsyncExecute(Task task, Object state)
   at Microsoft.Data.SqlClient.SqlDataReader.InvokeAsyncCall[T](SqlDataReaderBaseAsyncCallContext`1 context)
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithRowsAffectedOnlyAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
ClientConnectionId:1fcfd71b-b424-4a36-b4f1-894256d4e78f
Error Number:596,State:1,Class:21
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.SqlServer.Update.Internal.SqlServerModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Program.Main() in C:\local\code\AllTogetherNow\Daily\Daily.cs:line 55
   at Program.<Main>()

Process finished with exit code -532,462,766.

@ErikEJ
Copy link
Contributor

ErikEJ commented Feb 12, 2023

Msybe the new update pipeline should disable itself if any triggers are defined on any table?

@ErikEJ
Copy link
Contributor

ErikEJ commented Feb 12, 2023

Seems similar to #30253

@roji
Copy link
Member

roji commented Feb 13, 2023

The point here is that the only entity being saved (Office) doesn't have a trigger in the database. The trigger is on Employee, which is not being saved.

Thanks for clarying that, I missed that point.

But this doesn't work because a cascading update is defined from Office to Employee. So, the workaround, and it is a workaround, is to tell EF that Office has a trigger when it doesn't.

Cascading delete in this sample, right? Just to be sure I understand.

In any case yeah, this is unfortunate and I agree the above is a workaround. We could look into adding logic for detecting if there are any dependents with cascading delete, but that's starting to be a lot.

Msybe the new update pipeline should disable itself if any triggers are defined on any table?

We could, but I'm not sure I'd want to go that far...

@ajcvickers
Copy link
Contributor

Cascading delete in this sample, right? Just to be sure I understand

No, this is a cascading update:

CONSTRAINT [FK_Employee_Office_OfficeId] FOREIGN KEY ([OfficeId]) REFERENCES [Office] ([Id]) ON DELETE SET NULL

Cascade delete does not have this problem.

@ajcvickers
Copy link
Contributor

Note from triage: Covered by #29916, or by adding a dummy trigger on the parent table if turning off the behavior globally is not desired.

@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Feb 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants