I'm trying to implement hard delete for FullyAuditedEntity
Entity Test
. The primary key of Test
is Id
, which is being referred to a TestTest2
entity as a foreign key. When I'm trying to delete a record from Test
entity, it gives the below error.
I have followed this question for implementation.
TestAppService
public async Task DeleteTest(EntityDto<string> input)
{
using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.SoftDelete))
{
await _TestRepository.DeleteTest(input);
CurrentUnitOfWork.SaveChanges();
}
}
TestRepository
public async Task DeleteArticle(EntityDto input)
{
await DeleteAsync(x => x.Id == input.Id);
}
TestTest2
[Table("TestTest2")]
public class TestTest2 : FullAuditedEntity
{
[ForeignKey("TestId")]
public virtual Test Test { get; set; }
public virtual string TestId { get; set; }
[ForeignKey("Test2Id")]
public virtual Test2Details Test2s { get; set; }
public virtual int Test2Id { get; set; }
}
MyProjectDbContextModelSnapshot
modelBuilder.Entity("MyCompany.MyProject.Business.Model.Tests.TestTest2Association", b =>
{
b.HasOne("MyCompany.MyProject.Business.Model.Tests.Test", "Test")
.WithMany()
.HasForeignKey("TestId");
b.HasOne("MyCompany.MyProject.Business.Model.Test2s.Test2Details", "Test2s")
.WithMany()
.HasForeignKey("Test2Id")
.OnDelete(DeleteBehavior.Cascade);
});
ERROR 2018-02-28 18:10:09,840 [26 ] Mvc.ExceptionHandling.AbpExceptionFilter - An error occurred while updating the entries. See the inner exception for details. Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The DELETE statement conflicted with the REFERENCE constraint "FK_TestTest2_Test_TestId". The conflict occurred in database "MyProjectDb", table "dbo.TestTest2", column 'TestId'. The statement has been terminated. at System.Data.SqlClient.SqlConMyCompanytion.OnError(SqlException exception, Boolean breakConMyCompanytion, Action
1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConMyCompanytion.OnError(SqlException exception, Boolean breakConMyCompanytion, Action
1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConMyCompanytionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.ExecuteReader() at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConMyCompanytion conMyCompanytion, DbCommandMethod executeMethod, IReadOnlyDictionary
2 parameterValues) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConMyCompanytion conMyCompanytion, IReadOnlyDictionary2 parameterValues) at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConMyCompanytion conMyCompanytion) --- End of inner exception stack trace --- at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConMyCompanytion conMyCompanytion) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(Tuple
2 parameters) at Microsoft.EntityFrameworkCore.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func
3 verifySucceeded) at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.Execute[TState,TResult](IExecutionStrategy strategy, TState state, Func2 operation) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable
1 commandBatches, IRelationalConMyCompanytion conMyCompanytion) at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IReadOnlyList1 entries) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList
1 entriesToSave) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess) at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess) at Abp.EntityFrameworkCore.AbpDbContext.SaveChanges() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\AbpDbContext.cs:line 198 at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext`3.SaveChanges() in D:\Github\aspnetboilerplate\src\Abp.ZeroCore.EntityFrameworkCore\Zero\EntityFrameworkCore\AbpZeroCommonDbContext.cs:line 154 at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChangesInDbContext(DbContext dbContext) in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 159 at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChanges() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 60 at MyCompany.MyProject.Business.Services.Tests.TestAppService.d__12.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() INFO 2018-02-28 18:10:09,873 [26 ] etCore.Mvc.Internal.ObjectResultExecutor - Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. INFO 2018-02-28 18:10:09,922 [26 ] ore.Mvc.Internal.ControllerActionInvoker - Executed action MyCompany.MyProject.Business.Services.Tests.TestAppService.DeleteTest (MyCompany.MyProject.Business.Services) in 3940.4091ms INFO 2018-02-28 18:10:10,158 [26 ] soft.AspNetCore.Hosting.Internal.WebHost - Request finished in 4037.4507ms 500 application/json; charset=utf-8
Note: It should delete the entry from Test
and Test2
tables.
Update
The below anwer works pretty well but I have some specific requirement. Test
Entity Id
is being referred in other tables like TestTest2
, TestTest3
, TestTest4
, TestTest5
. When I delete a record from Test
table, it should delete from all tables. But I also need to call the other dependent tables ( for example TestTest2
, TestTest3
, TestTest4
, TestTest5
) Delete method to do some extra cleanup specific to that entity (for example TestTest2
, TestTest3
, TestTest4
, TestTest5
).
TestRepository
public async Task DeleteTest(EntityDto input)
{
await DeleteAsync(input.Id);
_TestTest2Repository.Delete(x => x.TestId == input.Id);
_TestTest3Repository.Delete(x => x.TestId == input.Id);
_TestTest4Repository.Delete(x => x.TestId == input.Id);
_TestTest5Repository.Delete(x => x.TestId == input.Id);
}
From the documentation on Cascade Delete:
For optional relationships: ClientSetNull (default)
- Effect on dependent/child in database: None
You have to configure the delete behavior using Fluent API in your DbContext:
modelBuilder.Entity<TestTest2>()
.HasOne(t => t.Test)
.WithMany()
.OnDelete(DeleteBehavior.Cascade);