I have a bug deleting an entity and soft delete does not seem to be applied. instead of marking the deleted field, it does hard delete
- ABP version 8.
- MVC single-Layer template
- EfCore
- when deleting an entity, I have the below exception being thrown by the Repository. It seems that the DBContext is being called twice.
- it also seems that the soft delete does not work at all
- System.InvalidOperationException
HResult=0x80131509
Message=A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
Source=Microsoft.EntityFrameworkCore
StackTrace:
at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable
1.Enumerator.MoveNext() at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable1 source, Boolean& found) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at Microsoft.EntityFrameworkCore.Internal.EntityFinder1.GetDatabaseValues(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.GetDatabaseValues() at Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.Reload() at Volo.Abp.EntityFrameworkCore.AbpDbContext1.ApplyAbpConceptsForDeletedEntity(EntityEntry entry) at Volo.Abp.EntityFrameworkCore.AbpDbContext1.PublishEventsForTrackedEntity(EntityEntry entry) at Volo.Abp.EntityFrameworkCore.AbpDbContext1.ChangeTracker_StateChanged(Object sender, EntityStateChangedEventArgs e) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.OnStateChanged(InternalEntityEntry internalEntityEntry, EntityState oldState) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.FireStateChanged(EntityState oldState) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable1 forceStateWhenUnknownKey, Nullable1 fallbackState) at Microsoft.EntityFrameworkCore.DbContext.RemoveRange(IEnumerable1 entities) at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository2.<DeleteManyAsync>d__27.MoveNext() at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository2.<DeleteAsync>d__36.MoveNext() at Castle.DynamicProxy.AsyncInterceptorBase.<ProceedAsynchronous>d__13.MoveNext() at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.<ProceedAsync>d__7.MoveNext() at Volo.Abp.Uow.UnitOfWorkInterceptor.<InterceptAsync>d__2.MoveNext() at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.<InterceptAsync>d__2.MoveNext() at Komatel.Perenco.TrackingApp.Services.CostCenterAppService.<DeleteCostCenter>d__9.MoveNext() in C:\Users\ktngo\OneDrive\Documents\Visual Studio 2022\Komatel.Perenco.TrackingApp\Komatel.Perenco.TrackingApp\Komatel.Perenco.TrackingApp\Services\CostCenterAppService.cs:line 127 at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state) at System.Threading.QueueUserWorkItemCallback.Execute() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
using Komatel.Perenco.TrackingApp.Entities;
using Komatel.Perenco.TrackingApp.Services.Dtos;
using Komatel.Perenco.TrackingApp.Services.Interfaces;
using Volo.Abp.Domain.Repositories;
using Komatel.Perenco.TrackingApp.ObjectMapping;
using Volo.Abp.Application.Dtos;
using Komatel.Perenco.TrackingApp.Data;
using Komatel.Perenco.TrackingApp.Entities.Interfaces;
namespace Komatel.Perenco.TrackingApp.Services
{
public class CostCenterAppService : TrackingAppAppService, ICostCenterAppService
{
private readonly ICostCenterRepository _costCenterRepository;
private readonly IRepository<ServiceCostCenter> _serviceCostCenterRepository;
public CostCenterAppService()
{ }
public CostCenterAppService(ICostCenterRepository CostCenterRepo, IRepository<ServiceCostCenter> serviceCostCenterRepo)
{
_costCenterRepository = CostCenterRepo;
_serviceCostCenterRepository = serviceCostCenterRepo;
}
//public async Task<List<CostCenterDto>> GetCostCentersAsync()
//{
// var costCenters = await _costCenterRepository.GetListAsync();
// var dtos = new List<CostCenterDto>();
// dtos = ObjectMapper.Map<List<CostCenter>, List<CostCenterDto>>(costCenters, dtos);
// return dtos;
//}
public async Task<PagedResultDto<CostCenterDto>> GetCostCentersAsync(GetCostCenterListDto input)
{
var costCenters = await _costCenterRepository.GetListAsync();
var dtos = new List<CostCenterDto>();
dtos = ObjectMapper.Map<List<CostCenter>, List<CostCenterDto>>(costCenters, dtos);
if (input.Sorting.IsNullOrWhiteSpace())
{
input.Sorting = nameof(CostCenter.Name);
}
var costs = await _costCenterRepository.GetListAsync(
input.SkipCount,
input.MaxResultCount,
input.Sorting,
input.Filter
);
var totalCount = input.Filter == null
? await _costCenterRepository.CountAsync()
: await _costCenterRepository.CountAsync(
cost => cost.Name.Contains(input.Filter));
return new PagedResultDto<CostCenterDto>(
totalCount,
ObjectMapper.Map<List<CostCenter>, List<CostCenterDto>>(costs)
);
}
public async Task<CostCenterDto> GetCostCenter(Guid Id)
{
var costCenters = await _costCenterRepository.GetAsync(Id);
var dto = ObjectMapper.Map<CostCenter, CostCenterDto>(costCenters);
return dto;
}
public async Task<List<ServiceCostCenterDto>> GetCostCentersAndServices(Guid costcenterid)
{
var serviceCostCenters = await _serviceCostCenterRepository.GetListAsync(c => c.CostCenterId == costcenterid);
var dtos = new List<ServiceCostCenterDto>();
dtos = ObjectMapper.Map<List<ServiceCostCenter>, List<ServiceCostCenterDto>>(serviceCostCenters, dtos);
return dtos;
}
public async void CreateCostCenterAsync(CostCenterDto dto)
{
var costcenter = ObjectMapper.Map<CostCenterDto, CostCenter>(dto);
await _costCenterRepository.InsertAsync(costcenter);
}
public async void UpdateCostCenter(CostCenterDto dto)
{
var costcenter = ObjectMapper.Map<CostCenterDto, CostCenter>(dto);
await _costCenterRepository.UpdateAsync(costcenter);
}
public async void DeleteCostCenter(Guid id)
{
await _costCenterRepository.DeleteAsync(x => x.Id == id);
}
Task<List<CostCenterDto>> ICostCenterAppService.GetCostCentersAsync()
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Komatel.Perenco.TrackingApp.Entities;
using Komatel.Perenco.TrackingApp.Entities.Interfaces;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Komatel.Perenco.TrackingApp.Data
{
public class EfCoreCostCenterRepository : EfCoreRepository<TrackingAppDbContext, CostCenter, Guid>, ICostCenterRepository
{
public EfCoreCostCenterRepository(IDbContextProvider<TrackingAppDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public async Task<List<CostCenter>> GetListAsync(int skipCount, int maxResultCount, string sorting, string filter)
{
var dbSet = await GetDbSetAsync();
return await dbSet
.WhereIf(
!filter.IsNullOrWhiteSpace(),
cost => cost.Name.Contains(filter)
)
.OrderBy(sorting)
.Skip(skipCount)
.Take(maxResultCount)
.ToListAsync();
}
}
}
hi
Please change all return type from async void to async Task .
hi @maliming , I need to change on the repositories and the Appservice ?
hi
You have to change all the code like this. Never use async void as the return type for async methods.
noted but now I am getting the following error with update method. "The data you have submitted has already changed by another user/client. Please discard the changes you've done and try from the beginning."
public async Task UpdateCostCenter(CostCenterDto dto)
{
var costcenter = _costCenterRepository.GetAsync(dto.Id);
ObjectMapper.Map<CostCenterDto, CostCenter>(dto, costcenter);
await _costCenterRepository.UpdateAsync(costcenter);
}
hello, will try the changes and advise. I suspect I was not properly mapping the objects with automapper.
https://docs.abp.io/en/abp/latest/Object-To-Object-Mapping