Browse Source

Merge pull request #19394 from abpframework/EntityCacheBase

`EnableTracking` if the `entity` has `ObjectExtensionInfo`.
pull/19454/head
maliming 3 years ago
committed by GitHub
parent
commit
7e715f8e10
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      docs/en/Entity-Framework-Core.md
  2. 42
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Caching/EntityCacheBase.cs
  3. 24
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Caching/EntityCacheServiceCollectionExtensions.cs
  4. 2
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Caching/EntityCacheWithoutCacheItem.cs

2
docs/en/Entity-Framework-Core.md

@ -753,6 +753,8 @@ public static class QADbContextModelCreatingExtensions
> If you call `ConfigureByConvention()` extension method (like `b.ConfigureByConvention()` for this example), ABP Framework internally calls the `ConfigureObjectExtensions` and `ConfigureEfCoreEntity` methods. It is a **best practice** to use the `ConfigureByConvention()` method since it also configures database mapping for base properties by convention.
> The `Object Extension` feature need the `Change Tracking`, which means you can't use the read-only repositories for the entities that have `extension properties(MapEfCoreProperty)`, Please see the [Repositories documentation](Repositories.md) to learn the change tracking behavior.
See the "*ConfigureByConvention Method*" section above for more information.
## Advanced Topics

42
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Caching/EntityCacheBase.cs

@ -1,8 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Uow;
namespace Volo.Abp.Domain.Entities.Caching;
@ -26,32 +28,52 @@ public abstract class EntityCacheBase<TEntity, TEntityCacheItem, TKey> :
Cache = cache;
UnitOfWorkManager = unitOfWorkManager;
}
public virtual async Task<TEntityCacheItem?> FindAsync(TKey id)
{
return await Cache.GetOrAddAsync(
id,
async () => MapToCacheItem(await Repository.FindAsync(id))!
);
async () =>
{
if (HasObjectExtensionInfo())
{
Repository.EnableTracking();
}
return MapToCacheItem(await Repository.FindAsync(id))!;
});
}
public virtual async Task<TEntityCacheItem> GetAsync(TKey id)
{
return (await Cache.GetOrAddAsync(
id,
async () => MapToCacheItem(await Repository.GetAsync(id))!
))!;
async () =>
{
if (HasObjectExtensionInfo())
{
Repository.EnableTracking();
}
return MapToCacheItem(await Repository.GetAsync(id))!;
}))!;
}
protected virtual bool HasObjectExtensionInfo()
{
return typeof(IHasExtraProperties).IsAssignableFrom(typeof(TEntity)) &&
ObjectExtensionManager.Instance.GetOrNull(typeof(TEntity)) != null;
}
protected abstract TEntityCacheItem? MapToCacheItem(TEntity? entity);
public async Task HandleEventAsync(EntityChangedEventData<TEntity> eventData)
{
if (eventData is EntityCreatedEventData<TEntity>)
{
return;
}
/* Why we are using double remove:
* First Cache.RemoveAsync drops the cache item in a unit of work.
* Some other application / thread may read the value from database and put it to the cache again
@ -59,12 +81,12 @@ public abstract class EntityCacheBase<TEntity, TEntityCacheItem, TKey> :
* The second Cache.RemoveAsync drops the cache item after the database transaction is complete.
* Only the second Cache.RemoveAsync may not be enough if the application crashes just after the UOW completes.
*/
await Cache.RemoveAsync(eventData.Entity.Id);
if(UnitOfWorkManager.Current != null)
{
await Cache.RemoveAsync(eventData.Entity.Id, considerUow: true);
}
}
}
}

24
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Caching/EntityCacheServiceCollectionExtensions.cs

@ -16,13 +16,8 @@ public static class EntityCacheServiceCollectionExtensions
DistributedCacheEntryOptions? cacheOptions = null)
where TEntity : Entity<TKey>
{
services
.TryAddTransient<
IEntityCache<TEntity, TKey>,
EntityCacheWithoutCacheItem<TEntity, TKey>
>();
services
.TryAddTransient<EntityCacheWithoutCacheItem<TEntity, TKey>>();
services.TryAddTransient<IEntityCache<TEntity, TKey>, EntityCacheWithoutCacheItem<TEntity, TKey>>();
services.TryAddTransient<EntityCacheWithoutCacheItem<TEntity, TKey>>();
services.Configure<AbpDistributedCacheOptions>(options =>
{
@ -43,13 +38,8 @@ public static class EntityCacheServiceCollectionExtensions
where TEntity : Entity<TKey>
where TEntityCacheItem : class
{
services
.TryAddTransient<
IEntityCache<TEntityCacheItem, TKey>,
EntityCacheWithObjectMapper<TEntity, TEntityCacheItem, TKey>
>();
services
.TryAddTransient<EntityCacheWithObjectMapper<TEntity, TEntityCacheItem, TKey>>();
services.TryAddTransient<IEntityCache<TEntityCacheItem, TKey>, EntityCacheWithObjectMapper<TEntity, TEntityCacheItem, TKey>>();
services.TryAddTransient<EntityCacheWithObjectMapper<TEntity, TEntityCacheItem, TKey>>();
services.Configure<AbpDistributedCacheOptions>(options =>
{
@ -65,11 +55,7 @@ public static class EntityCacheServiceCollectionExtensions
where TEntity : Entity<TKey>
where TEntityCacheItem : class
{
services
.TryAddTransient<
IEntityCache<TEntityCacheItem, TKey>,
EntityCacheWithObjectMapperContext<TObjectMapperContext, TEntity, TEntityCacheItem, TKey>
>();
services.TryAddTransient<IEntityCache<TEntityCacheItem, TKey>, EntityCacheWithObjectMapperContext<TObjectMapperContext, TEntity, TEntityCacheItem, TKey>>();
services.TryAddTransient<EntityCacheWithObjectMapperContext<TObjectMapperContext, TEntity, TEntityCacheItem, TKey>>();
services.Configure<AbpDistributedCacheOptions>(options =>

2
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Caching/EntityCacheWithoutCacheItem.cs

@ -20,6 +20,4 @@ public class EntityCacheWithoutCacheItem<TEntity, TKey> :
{
return entity;
}
}

Loading…
Cancel
Save