@maliming thank you for your suggestion.
In the end, the issue wasn't whether or not it was synchronous/asynchronous but rather that the repository inserts needed to work with a new object each time, rather than one object that got modified for each insert.
public async Task AssignOrUpdateRoles(CreateOrUpdateTeamUserRoleInput input)
{
input.AssignedTeamUserRoles.Where(n => n.Assigned == "true").ToList().ForEach(async i =>
{
var teamUserRole = new TeamUserRole
{
OrganizationUnitId = input.TeamUser.OrganizationUnitId,
TenantId = AbpSession.TenantId,
UserId = input.TeamUser.UserId,
RoleId = i.Id
};
if (!_teamUserRoleRepository.GetAll().Any(n => n.UserId == teamUserRole.UserId
&& n.RoleId == teamUserRole.RoleId
&& n.OrganizationUnitId == teamUserRole.OrganizationUnitId
&& (teamUserRole.TenantId == null || n.TenantId == teamUserRole.TenantId)))
{
await AssignRoles(teamUserRole);
}
}
);
}