为在其他实体中引用的实体实施硬删除
Implementation of Hard Delete for Entity which is being referred in other entity
我正在尝试为 FullyAuditedEntity
实体 Test
实施硬删除。 Test
的主键是 Id
,它被称为 TestTest2
实体作为外键。当我尝试从 Test
实体中删除一条记录时,出现以下错误。
我已按照 问题进行实施。
TestAppService
public async Task DeleteTest(EntityDto<string> input)
{
using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.SoftDelete))
{
await _TestRepository.DeleteTest(input);
CurrentUnitOfWork.SaveChanges();
}
}
测试库
public async Task DeleteArticle(EntityDto input)
{
await DeleteAsync(x => x.Id == input.Id);
}
测试测试2
[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, Action1 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
注意:应该删除Test
和Test2
tables.
中的条目
更新
下面的答案效果很好,但我有一些具体要求。 Test
实体 Id
在其他 table 中被引用,例如 TestTest2
、TestTest3
、TestTest4
、TestTest5
。当我从 Test
table 中删除一条记录时,它应该从所有 table 中删除。 但我还需要调用其他依赖的tables(例如TestTest2
、TestTest3
、TestTest4
、TestTest5
)删除方法来做一些特定于该实体的额外清理(例如 TestTest2
、TestTest3
、TestTest4
、TestTest5
)。
测试库
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);
}
来自 Cascade Delete 上的文档:
For optional relationships: ClientSetNull (default)
- Effect on dependent/child in database: None
您必须在 DbContext 中使用 Fluent API 配置删除行为:
modelBuilder.Entity<TestTest2>()
.HasOne(t => t.Test)
.WithMany()
.OnDelete(DeleteBehavior.Cascade);
我正在尝试为 FullyAuditedEntity
实体 Test
实施硬删除。 Test
的主键是 Id
,它被称为 TestTest2
实体作为外键。当我尝试从 Test
实体中删除一条记录时,出现以下错误。
我已按照
TestAppService
public async Task DeleteTest(EntityDto<string> input)
{
using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.SoftDelete))
{
await _TestRepository.DeleteTest(input);
CurrentUnitOfWork.SaveChanges();
}
}
测试库
public async Task DeleteArticle(EntityDto input)
{
await DeleteAsync(x => x.Id == input.Id);
}
测试测试2
[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
注意:应该删除Test
和Test2
tables.
更新
下面的答案效果很好,但我有一些具体要求。 Test
实体 Id
在其他 table 中被引用,例如 TestTest2
、TestTest3
、TestTest4
、TestTest5
。当我从 Test
table 中删除一条记录时,它应该从所有 table 中删除。 但我还需要调用其他依赖的tables(例如TestTest2
、TestTest3
、TestTest4
、TestTest5
)删除方法来做一些特定于该实体的额外清理(例如 TestTest2
、TestTest3
、TestTest4
、TestTest5
)。
测试库
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);
}
来自 Cascade Delete 上的文档:
For optional relationships: ClientSetNull (default)
- Effect on dependent/child in database: None
您必须在 DbContext 中使用 Fluent API 配置删除行为:
modelBuilder.Entity<TestTest2>()
.HasOne(t => t.Test)
.WithMany()
.OnDelete(DeleteBehavior.Cascade);