Hi, it does not work either. Won't update count.
hi
Try this:
private async Task UpdateVehicleCount(Guid shipmentId) { using (var uow = this.UnitOfWorkManager.Begin(requiresNew: true)) { var shipment = await this.ShipmentRepository.GetAsync(shipmentId); shipment.VehicleCount = shipment.Vehicles.Count; await this.ShipmentRepository.UpdateAsync(shipment); await uow.CompleteAsync(); } }
hi
Hi, I've tried this and doesn't work.
Can you share a simple project to show that?
Thanks.
liming.ma@volosoft.com
Hi, sorry for the delay. Sent simple project to show it via email.
hi
Can you call the
await UnitOfWorkManager.Current.SaveChangesAsync();afterDeleteAsync?eg:
await this.VehicleRepository.DeleteAsync(vehicleId); await UnitOfWorkManager.Current.SaveChangesAsync(); var shipment = await _shipmentRepository.GetAsync(shipmentId); var count = shipment.Vehicles.Count;
Hi, I've tried this and doesn't work. Only work around I have is to add the following which I'd rather not do, which uses what you told me
public class EfCoreShipmentRepository : EfCoreServiceRepository<CoreServiceDbContext, Shipment, Guid>, IShipmentRepository
{
    public EfCoreShipmentRepository(IDbContextProvider<CoreServiceDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }
    public override async Task<Shipment> GetAsync(Guid id, bool includeDetails = true, CancellationToken cancellationToken = default)
    {
        await this.UnitOfWorkManager.Current.SaveChangesAsync(cancellationToken);
        var dbContext = await this.GetDbContextAsync();
        var shipment = await base.GetAsync(id, includeDetails, cancellationToken);
        shipment.Vehicles = await dbContext.Vehicles
            .Where(x => x.ShipmentId == id)
            .ToListAsync(cancellationToken);
        return shipment;
    }
}
                        I'm encountering an issue related to ISoftDelete not working as expected in a parent-child relationship within the same execution context. I have an ABP 8.2.1 solution with multiple microservices. In this issue it is contained in one microservice application which is my core service.
Setup I have a CoreServiceDbContext configured as follows:
[ConnectionStringName(CoreServiceDbProperties.ConnectionStringName)]
public class CoreServiceDbContext : MyDbContext<CoreServiceDbContext>
{
    public CoreServiceDbContext(DbContextOptions<CoreServiceDbContext> options)
        : base(options)
    {
    }
    public DbSet<Shipment> Shipments { get; set; }
    public DbSet<Vehicle> Vehicles { get; set; }
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        builder.ConfigureCoreService();
    }
}
Extension method used in model creation:
public static class CoreServiceDbContextModelCreatingExtensions
{
    public static void ConfigureCoreService(this ModelBuilder builder)
    {
        Check.NotNull(builder, nameof(builder));
        if (builder.IsHostDatabase())
        {
            builder.Entity<Shipment>(b =>
            {
                b.ToTable("Shipments");
                b.HasMany(x => x.Vehicles)
                 .WithOne(x => x.Shipment)
                 .OnDelete(DeleteBehavior.Cascade);
                b.ConfigureByConvention();
            });
            builder.Entity<Vehicle>(b =>
            {
                b.ToTable("Vehicles");
                b.ConfigureByConvention();
            });
        }
    }
}
The parent entity Shipment looks like this:
public class Shipment : FullAuditedAggregateRoot<Guid>
{
    public virtual ICollection<Vehicle> Vehicles { get; set; }
    public virtual int VehicleCount { get; set; }
}
and Vehicle:
public class Vehicle : FullAuditedAggregateRoot<Guid>
{
   // More properties here
}
Repository Structure
The Vehicle entity is managed via a custom repository chain:
public interface IVehicleRepository : ICustomRepository<Vehicle, Guid> { }
public interface ICustomRepository<TEntity, TKey> : IRepository<TEntity, TKey>
    where TEntity : class, IEntity<TKey>
{
    Task<TEntity> GetAsync(TKey id, bool includeDetails, params Expression<Func<TEntity, object>>[] propertySelectors);
    Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails, params Expression<Func<TEntity, object>>[] propertySelectors);
}
EF Core Implementation:
public abstract class EfCoreServiceRepository<TDbContext, TEntity, TKey> : EfCoreRepository<TDbContext, TEntity, TKey>, ICustomRepository<TEntity, TKey>
    where TDbContext : IEfCoreDbContext
    where TEntity : class, IEntity<TKey>
{
    public EfCoreServiceRepository(IDbContextProvider<TDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }
}
public class EfCoreVehicleRepository : EfCoreServiceRepository<CoreServiceDbContext, Vehicle, Guid>, IVehicleRepository
{
    public EfCoreVehicleRepository(IDbContextProvider<CoreServiceDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }
}
The repository structure for Shipment is the same.
Problem
When I delete a Vehicle like this:
await this.VehicleRepository.DeleteAsync(vehicleId);
And then I fetch it's parent entity, the parent still includes the soft-deleted vehicle if the GetAsync from shipment repository is executed right after the delete, in the same async execution.
var shipment = await _shipmentRepository.GetAsync(shipmentId);
var count = shipment.Vehicles.Count; // Still includes recently soft-deleted vehicle, therefore this number is always 1 more than what it should be.
What I tried:
It appears that EF Core combined with ABP does not re-evaluate global query filter ISoftDelete for navigation properties.