Browse Source

Merge pull request #24473 from abpframework/auto-merge/rel-10-0/4217

Merge branch dev with rel-10.0
pull/24475/head
Ma Liming 1 month ago
committed by GitHub
parent
commit
dc8f467093
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 11
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  2. 16
      framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDatabaseCollection.cs
  3. 22
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs

11
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -686,6 +686,12 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
return;
}
string? concurrencyStamp = null;
if (entry.Entity is IHasConcurrencyStamp hasConcurrencyStamp)
{
concurrencyStamp = hasConcurrencyStamp.ConcurrencyStamp;
}
ExtraPropertyDictionary? originalExtraProperties = null;
if (entry.Entity is IHasExtraProperties)
{
@ -694,6 +700,11 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
entry.Reload();
if (concurrencyStamp != null && entry.Entity is IHasConcurrencyStamp)
{
ObjectHelper.TrySetProperty(entry.Entity.As<IHasConcurrencyStamp>(), x => x.ConcurrencyStamp, () => concurrencyStamp);
}
if (entry.Entity is IHasExtraProperties)
{
ObjectHelper.TrySetProperty(entry.Entity.As<IHasExtraProperties>(), x => x.ExtraProperties, () => originalExtraProperties);

16
framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDatabaseCollection.cs

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Domain.Repositories.MemoryDb;
@ -37,10 +38,21 @@ public class MemoryDatabaseCollection<TEntity> : IMemoryDatabaseCollection<TEnti
public void Update(TEntity entity)
{
if (_dictionary.ContainsKey(GetEntityKey(entity)))
if (!_dictionary.ContainsKey(GetEntityKey(entity)))
{
_dictionary[GetEntityKey(entity)] = _memoryDbSerializer.Serialize(entity);
return;
}
var originalEntity = _memoryDbSerializer.Deserialize(_dictionary[GetEntityKey(entity)], typeof(TEntity)).As<TEntity>();
if (entity is IHasConcurrencyStamp hasConcurrencyStamp && originalEntity is IHasConcurrencyStamp originalHasConcurrencyStamp)
{
if (hasConcurrencyStamp.ConcurrencyStamp != originalHasConcurrencyStamp.ConcurrencyStamp)
{
throw new AbpDbConcurrencyException("Database operation expected to affect 1 row but actually affected 0 row. Data may have been modified or deleted since entities were loaded. This exception has been thrown on optimistic concurrency check.");
}
}
_dictionary[GetEntityKey(entity)] = _memoryDbSerializer.Serialize(entity);
}
public void Remove(TEntity entity)

22
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs

@ -139,4 +139,26 @@ public abstract class SoftDelete_Tests<TStartupModule> : TestAppTestBase<TStartu
douglas.Phones.ShouldNotBeEmpty();
}
}
[Fact]
public async Task Soft_Delete_Should_Check_Concurrency()
{
var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId);
douglas.ConcurrencyStamp.ShouldNotBeNull();
douglas.ConcurrencyStamp = Guid.NewGuid().ToString();
await Assert.ThrowsAsync<AbpDbConcurrencyException>(async () =>
{
await PersonRepository.DeleteAsync(douglas);
});
douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId);
douglas.ConcurrencyStamp.ShouldNotBeNull();
// Modify the entity to verify that a changed entity with a correct ConcurrencyStamp
// can still be soft deleted without raising a concurrency exception.
douglas.ChangeName("Changed Name");
// Try again with the correct ConcurrencyStamp - this will not throw an exception
await PersonRepository.DeleteAsync(douglas);
}
}

Loading…
Cancel
Save