-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
Hi team, I'm not sure if this is a bug or the expected behavior, but I'm seeing an inconsistency between CountAsync()
and ToListAsync()
when working with entities that use ISoftDelete
, especially when they are related via .Include(...)
.
public async Task<GetListGuestTasksOutputDto> GetListAsync(GetListGuestTasksInputDto input)
{
var query = _workflowCardTaskRepository.GetAll()
.Include(x => x.WorkflowCard)
.Include(x => x.CurrentWorkflowPhase.Workflow)
.Include(x => x.CreatorUser)
.Where(x =>
x.AssigneeUserId == AbpSession.UserId &&
x.Status == input.Status
);
var totalCount = await query.CountAsync(); // result: 2
// result: 1 record
var entities = await query
.OrderBy(x => x.CreationTime)
.Skip(input.SkipCount)
.Take(input.MaxResultCount)
.ToListAsync();
var result = new GetListGuestTasksOutputDto { Total = totalCount };
foreach (var item in entities)
{
var dto = ObjectMapper.Map<WorkflowCardTaskDto>(item);
result.Items.Add(dto);
}
return result;
}
Expected Behavior
When querying through IRepository<T>
, the global filter for ISoftDelete
should be consistent across .CountAsync()
and .ToListAsync()
, including when the ISoftDelete
entity is nested through .Include()
or navigation properties.
Actual Behavior
CountAsync()
does not respect ISoftDelete
filters of related entities included through navigation, while ToListAsync()
does — this leads to divergent results and forces the developer to manually add extra filters for all possible nested deletions.
Questions
- Is there a supported pattern to automatically apply
ISoftDelete
filters on related entities in EF Core when usingInclude()
? - Is this something ABP can extend or wrap at the repository level (e.g., through
IRepository<T>
orIQueryable<T>
extensions)? - If not, is the recommendation to always filter nested
IsDeleted
properties manually?
Workaround Used
We added manual filters for all involved navigations:
.Where(x =>
x.AssigneeUserId == AbpSession.UserId &&
x.Status == input.Status &&
!x.CurrentWorkflowPhase.IsDeleted &&
!x.WorkflowPhaseTask.IsDeleted &&
!x.WorkflowCard.IsDeleted &&
!x.WorkflowCard.Workflow.IsDeleted
);
Environment
ABP Version: 9.0
EF Core Version: 8.0
Database Provider: SQL Server