diff --git a/src/Connected.Entities/Caching/EntityCacheClient.cs b/src/Connected.Entities/Caching/EntityCacheClient.cs index 78183f3..9b20564 100644 --- a/src/Connected.Entities/Caching/EntityCacheClient.cs +++ b/src/Connected.Entities/Caching/EntityCacheClient.cs @@ -10,118 +10,120 @@ using System.Collections.Immutable; namespace Connected.Entities.Caching; public abstract class EntityCacheClient : StatefulCacheClient, IEntityCacheClient - where TEntity : class, IPrimaryKey, IEntity - where TPrimaryKey : notnull + where TEntity : class, IPrimaryKey, IEntity + where TPrimaryKey : notnull { - protected EntityCacheClient(IEntityCacheContext context, string key) : base(context.Cache, key) - { - Context = context; - } - - private IEntityCacheContext Context { get; } - - protected override sealed async Task OnInitializing() - { - using var ctx = Context.ContextProvider.Create(); - - var transaction = ctx.GetService(); - - try - { - if (await OnInitializing(ctx) is ImmutableList ds) - { - foreach (var r in ds) - Set(r.Id, r, TimeSpan.Zero); - } - - if (transaction is not null) - await transaction.Commit(); - } - catch - { - if (transaction is not null) - await transaction.Rollback(); - - throw; - } - } - - protected virtual async Task?> OnInitializing(IContext context) - { - if (context.GetService() is not IStorageProvider db) - return default; - - return await (from dc in db.Open() - select dc).AsEntities(); - } - - protected override async Task OnInvalidate(TPrimaryKey id) - { - using var ctx = Context.ContextProvider.Create(); - var transaction = ctx.GetService(); - - try - { - if (OnInvalidating(ctx, id) is TEntity entity && entity is IPrimaryKey pk) - Set(pk.Id, entity, TimeSpan.Zero); - - if (transaction is not null) - await transaction.Commit(); - } - catch - { - if (transaction is not null) - await transaction.Rollback(); - - throw; - } - } - - protected virtual async Task OnInvalidating(IContext context, TPrimaryKey id) - { - if (context.GetService() is not IStorageProvider provider) - return default; - - return await (from dc in provider.Open() - where TypeComparer.Compare(dc.Id, id) - select dc).AsEntity(); - } - - async Task IEntityCacheClient.Refresh(TPrimaryKey id) - { - await Refresh(id); - } - - async Task IEntityCacheClient.Remove(TPrimaryKey id) - { - await Remove(id); - } - - protected override void Set(TPrimaryKey id, TEntity instance) - { - Set(id, instance, TimeSpan.Zero); - } - - protected override void Set(TPrimaryKey id, TEntity instance, TimeSpan duration) - { - if (instance is IConcurrentEntity concurrent) - { - if (Get(id) is TEntity existing && existing is IConcurrentEntity existingConcurrent) - { - lock (existingConcurrent) - { - if (existingConcurrent.Sync != concurrent.Sync) - throw new InvalidOperationException(SR.ErrConcurrent); - - concurrent.GetType().GetProperty(nameof(IConcurrentEntity.Sync))?.SetValue(concurrent, concurrent.Sync + 1); - - Set(id, instance, duration); - - return; - } - } - } - - base.Set(id, instance, duration); - } + protected EntityCacheClient(IEntityCacheContext context, string key) : base(context.Cache, key) + { + Context = context; + } + + private IEntityCacheContext Context { get; } + + protected override sealed async Task OnInitializing() + { + using var ctx = Context.ContextProvider.Create(); + + var transaction = ctx.GetService(); + + try + { + if (await OnInitializing(ctx) is ImmutableList ds) + { + foreach (var r in ds) + Set(r.Id, r, TimeSpan.Zero); + } + + if (transaction is not null) + await transaction.Commit(); + } + catch + { + if (transaction is not null) + await transaction.Rollback(); + + throw; + } + } + + protected virtual async Task?> OnInitializing(IContext context) + { + if (context.GetService() is not IStorageProvider db) + return default; + + return await (from dc in db.Open() + select dc).AsEntities(); + } + + protected override async Task OnInvalidate(TPrimaryKey id) + { + using var ctx = Context.ContextProvider.Create(); + var transaction = ctx.GetService(); + + try + { + if (OnInvalidating(ctx, id) is TEntity entity && entity is IPrimaryKey pk) + Set(pk.Id, entity, TimeSpan.Zero); + + if (transaction is not null) + await transaction.Commit(); + } + catch + { + if (transaction is not null) + await transaction.Rollback(); + + throw; + } + } + + protected virtual async Task OnInvalidating(IContext context, TPrimaryKey id) + { + if (context.GetService() is not IStorageProvider provider) + return default; + + var entities = provider.Open().AsEntities(); + + return await (from dc in provider.Open() + where TypeComparer.Compare(dc.Id, id) + select dc).AsEntity(); + } + + async Task IEntityCacheClient.Refresh(TPrimaryKey id) + { + await Refresh(id); + } + + async Task IEntityCacheClient.Remove(TPrimaryKey id) + { + await Remove(id); + } + + protected override void Set(TPrimaryKey id, TEntity instance) + { + Set(id, instance, TimeSpan.Zero); + } + + protected override void Set(TPrimaryKey id, TEntity instance, TimeSpan duration) + { + if (instance is IConcurrentEntity concurrent) + { + if (Get(id) is TEntity existing && existing is IConcurrentEntity existingConcurrent) + { + lock (existingConcurrent) + { + if (existingConcurrent.Sync != concurrent.Sync) + throw new InvalidOperationException(SR.ErrConcurrent); + + concurrent.GetType().GetProperty(nameof(IConcurrentEntity.Sync))?.SetValue(concurrent, concurrent.Sync + 1); + + Set(id, instance, duration); + + return; + } + } + } + + base.Set(id, instance, duration); + } }