From c6d46a0b85b4ddf1559791cc2e8f2bc632e05ddc Mon Sep 17 00:00:00 2001 From: dingsongjie Date: Wed, 26 Feb 2020 17:15:26 +0800 Subject: [PATCH] 添加 更多功能 --- samples/apis/Backet.Api/Controllers/BacketController.cs | 15 +++------------ samples/apis/Backet.Api/Domain/AggregatesModels/BacketAggregate/Backet.cs | 2 +- samples/apis/Backet.Api/Grains/Abstraction/IAddBacketGrain.cs | 13 +++++++++++++ samples/apis/Backet.Api/Grains/Abstraction/IBacketGrain.cs | 1 - samples/apis/Backet.Api/Grains/AddBacketGrain.cs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ samples/apis/Backet.Api/Grains/BacketGrain.cs | 4 ++++ samples/apis/Backet.Api/Program.cs | 2 +- samples/apis/Backet.Api/Startup.cs | 8 +++++--- src/Pole.Core/EventBus/EventBuffer.cs | 8 ++++---- src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/GrainStorageConvention.cs | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/IGrainStorageConvention.cs | 34 +++++++++++++++++++++++++++++++++- src/Pole.Orleans.Provider.EntityframeworkCore/Extensions/GrainStorageOptionsExtensions.cs | 3 ++- src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorage.cs | 4 ++-- src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorageOptions.cs | 3 +++ src/Pole.Orleans.Provider.EntityframeworkCore/GrainStoragePostConfigureOptions.cs | 26 ++++++++++++++++++++++++++ 15 files changed, 299 insertions(+), 26 deletions(-) create mode 100644 samples/apis/Backet.Api/Grains/Abstraction/IAddBacketGrain.cs create mode 100644 samples/apis/Backet.Api/Grains/AddBacketGrain.cs diff --git a/samples/apis/Backet.Api/Controllers/BacketController.cs b/samples/apis/Backet.Api/Controllers/BacketController.cs index 253a0e6..1cf72c1 100644 --- a/samples/apis/Backet.Api/Controllers/BacketController.cs +++ b/samples/apis/Backet.Api/Controllers/BacketController.cs @@ -51,24 +51,15 @@ namespace Backet.Api.Controllers { var newId = Guid.NewGuid().ToString("N").ToLower(); backet.Id = newId; - //var entity = await backetDbContext.Backets.AsNoTracking().Include(box => box.BacketItems).SingleOrDefaultAsync(m => m.Id == "222"); - - ////using (NpgsqlConnection conn = new NpgsqlConnection("Server=192.168.0.248;Port=5432;Username=postgres;Password=comteck2020!@#;Database=Pole-Backet;Enlist=True;Timeout=0;Command Timeout=600")) - ////{ - //// await conn.OpenAsync(); - //// var teams = await conn.QueryAsync("SELECT * FROM \"public\".\"Backet\" where \"Id\" =@Id", new { Id = newId }); - //// //var teams = await conn.ExecuteAsync("SELECT 1"); - ////} - var grain = clusterClient.GetGrain(newId); + var grain = clusterClient.GetGrain(newId); return grain.AddBacket(backet); - //return true; } [HttpPost("api/backet/UpdateBacket")] public Task UpdateBacket() { - var id = "da8a489fa7b4409294ee1b358fbbfba5"; + var id = "67bbf594246441a18d7b6c74a277d06a"; var grain = clusterClient.GetGrain(id); - return grain.UpdateBacket("88"); + return grain.UpdateBacket("99"); } [HttpPost("api/backet/AddItem")] public Task AddItem() diff --git a/samples/apis/Backet.Api/Domain/AggregatesModels/BacketAggregate/Backet.cs b/samples/apis/Backet.Api/Domain/AggregatesModels/BacketAggregate/Backet.cs index 02fce3e..b6596a6 100644 --- a/samples/apis/Backet.Api/Domain/AggregatesModels/BacketAggregate/Backet.cs +++ b/samples/apis/Backet.Api/Domain/AggregatesModels/BacketAggregate/Backet.cs @@ -33,7 +33,7 @@ namespace Backet.Api.Domain.AggregatesModel.BacketAggregate } public string UserId { get; set; } public List BacketItems { get; private set; } = new List(); - public long TotalPrice { get; private set; } + public long TotalPrice { get; set; } internal void RemoveFirstItem() { diff --git a/samples/apis/Backet.Api/Grains/Abstraction/IAddBacketGrain.cs b/samples/apis/Backet.Api/Grains/Abstraction/IAddBacketGrain.cs new file mode 100644 index 0000000..eda64a0 --- /dev/null +++ b/samples/apis/Backet.Api/Grains/Abstraction/IAddBacketGrain.cs @@ -0,0 +1,13 @@ +using Orleans; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Backet.Api.Grains.Abstraction +{ + public interface IAddBacketGrain : IGrainWithStringKey + { + Task AddBacket(BacketDto backet); + } +} diff --git a/samples/apis/Backet.Api/Grains/Abstraction/IBacketGrain.cs b/samples/apis/Backet.Api/Grains/Abstraction/IBacketGrain.cs index c605518..445d170 100644 --- a/samples/apis/Backet.Api/Grains/Abstraction/IBacketGrain.cs +++ b/samples/apis/Backet.Api/Grains/Abstraction/IBacketGrain.cs @@ -8,7 +8,6 @@ namespace Backet.Api.Grains.Abstraction { public interface IBacketGrain: IGrainWithStringKey { - Task AddBacket(BacketDto backet); Task UpdateBacket(string userId); Task AddBacketItem(string productId, string productName, long price); Task RemoveFirstItem(); diff --git a/samples/apis/Backet.Api/Grains/AddBacketGrain.cs b/samples/apis/Backet.Api/Grains/AddBacketGrain.cs new file mode 100644 index 0000000..6f73eba --- /dev/null +++ b/samples/apis/Backet.Api/Grains/AddBacketGrain.cs @@ -0,0 +1,49 @@ +using Backet.Api.Grains.Abstraction; +using Backet.Api.Infrastructure; +using Orleans; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Backet.Api.Domain.Event; +using Pole.Core.UnitOfWork; +using Pole.Core.EventBus.Transaction; +using Pole.Core.EventBus; + +namespace Backet.Api.Grains +{ + public class AddBacketGrain : Grain, IAddBacketGrain + { + public async Task AddBacket(BacketDto backetDto) + { + using (var scope = ServiceProvider.CreateScope()) + { + var unitOfWork = scope.ServiceProvider.GetRequiredService(); + var dbTransactionAdapter = scope.ServiceProvider.GetRequiredService(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + var bus = scope.ServiceProvider.GetRequiredService(); + using (var transaction = await dbContext.Database.BeginTransactionAsync()) + { + dbTransactionAdapter.DbTransaction = transaction; + unitOfWork.Enlist(dbTransactionAdapter, bus); + Backet.Api.Domain.AggregatesModel.BacketAggregate.Backet backet = new Backet.Api.Domain.AggregatesModel.BacketAggregate.Backet + { + Id = backetDto.Id, + UserId = backetDto.UserId + }; + if (backetDto.BacketItems == null || backetDto.BacketItems.Count == 0) return false; + backetDto.BacketItems.ForEach(item => + { + backet.AddBacketItem(item.ProductId, item.ProductName, item.Price); + }); + dbContext.Backets.Add(backet); + await bus.Publish(new BacketCreatedEvent() { BacketId = backet.Id }); + await unitOfWork.CompeleteAsync(); + } + return true; + } + + } + } +} diff --git a/samples/apis/Backet.Api/Grains/BacketGrain.cs b/samples/apis/Backet.Api/Grains/BacketGrain.cs index 03bd0c6..42b5aae 100644 --- a/samples/apis/Backet.Api/Grains/BacketGrain.cs +++ b/samples/apis/Backet.Api/Grains/BacketGrain.cs @@ -1,5 +1,6 @@ using Backet.Api.Domain.Event; using Backet.Api.Grains.Abstraction; +using Orleans.Providers; using Pole.Core.Grains; using System; using System.Collections.Generic; @@ -8,10 +9,12 @@ using System.Threading.Tasks; namespace Backet.Api.Grains { + [StorageProvider(ProviderName = "ef")] public class BacketGrain : PoleGrain, IBacketGrain { public async Task AddBacket(BacketDto backetDto) { + if (State != null) return false; Backet.Api.Domain.AggregatesModel.BacketAggregate.Backet backet = new Backet.Api.Domain.AggregatesModel.BacketAggregate.Backet @@ -52,6 +55,7 @@ namespace Backet.Api.Grains { if (State == null) return false; State.UserId = userId; + State.TotalPrice++; State.ModifyItemProductId(userId); Update(State); await WriteStateAsync(); diff --git a/samples/apis/Backet.Api/Program.cs b/samples/apis/Backet.Api/Program.cs index f61a71b..1ca150e 100644 --- a/samples/apis/Backet.Api/Program.cs +++ b/samples/apis/Backet.Api/Program.cs @@ -25,7 +25,7 @@ namespace Backet.Api .UseOrleans(siloBuilder => { siloBuilder.UseLocalhostClustering(); - siloBuilder.AddEfGrainStorageAsDefault(); + siloBuilder.AddEfGrainStorage("ef"); }) .ConfigureWebHostDefaults(webBuilder => { diff --git a/samples/apis/Backet.Api/Startup.cs b/samples/apis/Backet.Api/Startup.cs index 46fa49f..e29b3e0 100644 --- a/samples/apis/Backet.Api/Startup.cs +++ b/samples/apis/Backet.Api/Startup.cs @@ -27,7 +27,8 @@ namespace Backet.Api services.AddDbContextPool(options => options.UseNpgsql(Configuration["postgres:write"])); services.AddControllers(); - services.AddPole(config => { + services.AddPole(config => + { config.AddRabbitMQ(option => { option.Hosts = new string[1] { Configuration["RabbitmqConfig:HostAddress"] }; @@ -40,8 +41,9 @@ namespace Backet.Api services.ConfigureGrainStorageOptions( options => { - options.UseQuery(context => context.Backets.AsNoTracking() - .Include(box => box.BacketItems)); + options.UseQuery(context => context.Backets + .Include(box => box.BacketItems), context => context.Backets.AsNoTracking() + .Include(box => box.BacketItems)); options.IsRelatedData = true; }); } diff --git a/src/Pole.Core/EventBus/EventBuffer.cs b/src/Pole.Core/EventBus/EventBuffer.cs index 5b6b4f7..9a2e8d6 100644 --- a/src/Pole.Core/EventBus/EventBuffer.cs +++ b/src/Pole.Core/EventBus/EventBuffer.cs @@ -109,7 +109,7 @@ namespace Pole.Core.EventBus } private async Task ExecuteCore(List eventEntities) { - logger.LogError($"Begin ExecuteCore Count:{eventEntities.Count} "); + logger.LogTrace($"Begin ExecuteCore Count:{eventEntities.Count} "); var events = eventEntities.Select(entity => { var eventContentBytes = Encoding.UTF8.GetBytes(entity.Content); @@ -125,9 +125,9 @@ namespace Pole.Core.EventBus entity.StatusName = nameof(EventStatus.Published); entity.ExpiresAt = DateTime.UtcNow.AddSeconds(options.PublishedEventsExpiredAfterSeconds); }); - logger.LogError($"Begin BulkPublish {DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} "); + logger.LogTrace($"Begin BulkPublish {DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} "); await producer.BulkPublish(events); - logger.LogError($"Begin BulkPublish {DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} "); + logger.LogTrace($"Begin BulkPublish {DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} "); if (eventEntities.Count > 10) { await eventStorage.BulkChangePublishStateAsync(eventEntities); @@ -137,7 +137,7 @@ namespace Pole.Core.EventBus await eventStorage.ChangePublishStateAsync(eventEntities); } - logger.LogError($"End ExecuteCore {DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} Count:{eventEntities.Count} "); + logger.LogTrace($"End ExecuteCore {DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} Count:{eventEntities.Count} "); } } } diff --git a/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/GrainStorageConvention.cs b/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/GrainStorageConvention.cs index f1fcee9..b547042 100644 --- a/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/GrainStorageConvention.cs +++ b/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/GrainStorageConvention.cs @@ -60,6 +60,33 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions null, dbSetPropertyInfo.GetMethod); + // create final delegate which chains dbSet getter and no tracking delegates + return dbSetDelegate; + } + + + + public Func> CreateDefaultDbSetNoTrackingAccessorFunc() + where TContext : DbContext + where TEntity : class + { + Type contextType = typeof(TContext); + + // Find a dbSet as default + PropertyInfo dbSetPropertyInfo = + contextType + .GetProperties(BindingFlags.Public | BindingFlags.Instance) + .FirstOrDefault(pInfo => pInfo.PropertyType == typeof(DbSet)); + + if (dbSetPropertyInfo == null) + throw new GrainStorageConfigurationException($"Could not find A property of type \"{typeof(DbSet).FullName}\" " + + $"on context with type \"{typeof(TContext).FullName}\""); + + var dbSetDelegate = (Func>)Delegate.CreateDelegate( + typeof(Func>), + null, + dbSetPropertyInfo.GetMethod); + // set queries as no tracking MethodInfo noTrackingMethodInfo = (typeof(GrainStorageConvention).GetMethod(nameof(AsNoTracking)) ?? throw new Exception("Impossible")) @@ -176,6 +203,101 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions throw new InvalidOperationException($"Unexpected grain type \"{typeof(TGrain).FullName}\""); } + public Func> CreatePreCompiledDefaultReadStateNoTrackingFunc(GrainStorageOptions options) + where TContext : DbContext + where TEntity : class + { + if (typeof(IGrainWithGuidKey).IsAssignableFrom(typeof(TGrain))) + { + if (options.GuidKeySelector == null) + throw new GrainStorageConfigurationException($"GuidKeySelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + + Func> compiledQuery + = CreateCompiledQuery(options); + + return (TContext context, IAddressable grainRef) => + { + Guid key = grainRef.GetPrimaryKey(); + return compiledQuery(context, key); + }; + } + + if (typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(typeof(TGrain))) + { + if (options.GuidKeySelector == null) + throw new GrainStorageConfigurationException($"GuidKeySelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + if (options.KeyExtSelector == null) + throw new GrainStorageConfigurationException($"KeyExtSelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + + Func> compiledQuery + = CreateCompiledCompoundQuery(options); + + return (TContext context, IAddressable grainRef) => + { + Guid key = grainRef.GetPrimaryKey(out string keyExt); + return compiledQuery(context, key, keyExt); + }; + } + + if (typeof(IGrainWithIntegerKey).IsAssignableFrom(typeof(TGrain))) + { + if (options.LongKeySelector == null) + throw new GrainStorageConfigurationException($"LongKeySelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + + Func> compiledQuery + = CreateCompiledQuery(options); + + return (TContext context, IAddressable grainRef) => + { + long key = grainRef.GetPrimaryKeyLong(); + return compiledQuery(context, key); + }; + } + + if (typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(typeof(TGrain))) + { + if (options.LongKeySelector == null) + throw new GrainStorageConfigurationException($"LongKeySelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + if (options.KeyExtSelector == null) + throw new GrainStorageConfigurationException($"KeyExtSelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + + Func> compiledQuery + = CreateCompiledCompoundQuery(options); + + return (TContext context, IAddressable grainRef) => + { + long key = grainRef.GetPrimaryKeyLong(out string keyExt); + return compiledQuery(context, key, keyExt); + }; + } + + if (typeof(IGrainWithStringKey).IsAssignableFrom(typeof(TGrain))) + { + if (options.KeyExtSelector == null) + throw new GrainStorageConfigurationException($"KeyExtSelector is not defined for " + + $"{typeof(GrainStorageOptions).FullName}"); + Func> compiledQuery = null; + + compiledQuery = CreateCompiledQuery(options); + + + + + return (TContext context, IAddressable grainRef) => + { + string keyExt = grainRef.GetPrimaryKeyString(); + return compiledQuery(context, keyExt); + }; + } + + throw new InvalidOperationException($"Unexpected grain type \"{typeof(TGrain).FullName}\""); + } public virtual Func> CreatePreCompiledDefaultReadStateFunc( @@ -480,7 +602,36 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions return EF.CompileAsyncQuery(lambdaExpression); } + private static Func> CreateCompiledCompoundNoTrackingQuery( + GrainStorageOptions options) + where TContext : DbContext + where TEntity : class + { + var contextParameter = Expression.Parameter(typeof(TContext), "context"); + var keyParameter = Expression.Parameter(typeof(TKey), "grainKey"); + var keyExtParameter = Expression.Parameter(typeof(string), "grainKeyExt"); + var predicate = CreateCompoundKeyPredicate( + options, + keyParameter, + keyExtParameter); + var queryable = Expression.Call( + options.DbSetNoTrackingAccessor.Method, + Expression.Constant(options.DbSetNoTrackingAccessor), + contextParameter); + + var compiledLambdaBody = Expression.Call( + typeof(Queryable).GetMethods().Single(mi => + mi.Name == nameof(Queryable.SingleOrDefault) && mi.GetParameters().Count() == 2) + .MakeGenericMethod(typeof(TEntity)), + queryable, + Expression.Quote(predicate)); + + var lambdaExpression = Expression.Lambda>( + compiledLambdaBody, contextParameter, keyParameter, keyExtParameter); + + return EF.CompileAsyncQuery(lambdaExpression); + } private static Expression> CreateCompoundKeyPredicate( GrainStorageOptions options, ParameterExpression grainKeyParam, @@ -708,6 +859,8 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions return new string(c); } + + #endregion } } diff --git a/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/IGrainStorageConvention.cs b/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/IGrainStorageConvention.cs index 8c1b351..4313865 100644 --- a/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/IGrainStorageConvention.cs +++ b/src/Pole.Orleans.Provider.EntityframeworkCore/Conventions/IGrainStorageConvention.cs @@ -24,6 +24,18 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions where TContext : DbContext where TEntity : class; + /// + /// Creates a method that returns an IQueryable' + /// against type. + /// + /// + /// + /// + Func> + CreateDefaultDbSetNoTrackingAccessorFunc() + where TContext : DbContext + where TEntity : class; + Func> CreateDefaultReadStateFunc( GrainStorageOptions options) @@ -31,11 +43,17 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions where TEntity : class; Func> - CreatePreCompiledDefaultReadStateFunc( + CreatePreCompiledDefaultReadStateNoTrackingFunc( GrainStorageOptions options) where TContext : DbContext where TEntity : class; + Func> + CreatePreCompiledDefaultReadStateFunc( + GrainStorageOptions options) + where TContext : DbContext + where TEntity : class; + void SetDefaultKeySelectors( GrainStorageOptions options) where TContext : DbContext @@ -102,6 +120,17 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions Func> CreateDefaultDbSetAccessorFunc(); + + /// + /// Creates a method that returns an IQueryable' + /// against type. + /// + /// + /// + /// + Func> + CreateDefaultDbSetNoTrackingAccessorFunc(); + /// /// Creates a method that generates an expression to be used by entity framework to /// fetch a single state. @@ -116,6 +145,9 @@ namespace Pole.Orleans.Provider.EntityframeworkCore.Conventions Func> CreatePreCompiledDefaultReadStateFunc( GrainStorageOptions options); + Func> CreatePreCompiledDefaultReadStateNoTrackingFunc( + GrainStorageOptions options); + void SetDefaultKeySelector(GrainStorageOptions options); Action GetSetterFunc(); diff --git a/src/Pole.Orleans.Provider.EntityframeworkCore/Extensions/GrainStorageOptionsExtensions.cs b/src/Pole.Orleans.Provider.EntityframeworkCore/Extensions/GrainStorageOptionsExtensions.cs index b7ea6fd..189a6ed 100644 --- a/src/Pole.Orleans.Provider.EntityframeworkCore/Extensions/GrainStorageOptionsExtensions.cs +++ b/src/Pole.Orleans.Provider.EntityframeworkCore/Extensions/GrainStorageOptionsExtensions.cs @@ -13,11 +13,12 @@ namespace Pole.Orleans.Provider.EntityframeworkCore { public static GrainStorageOptions UseQuery( this GrainStorageOptions options, - Func>queryFunc) + Func>queryFunc, Func> noTrackingQueryFunc) where TContext : DbContext where TGrainState : class { options.DbSetAccessor = queryFunc; + options.DbSetNoTrackingAccessor = noTrackingQueryFunc; return options; } diff --git a/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorage.cs b/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorage.cs index 73d8d74..b752649 100644 --- a/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorage.cs +++ b/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorage.cs @@ -52,7 +52,7 @@ namespace Pole.Orleans.Provider.EntityframeworkCore using (IServiceScope scope = _scopeFactory.CreateScope()) using (var context = scope.ServiceProvider.GetRequiredService()) { - TEntity entity = await _options.ReadStateAsync(context, grainReference) + TEntity entity = await _options.ReadStateNoTrackingAsync(context, grainReference) .ConfigureAwait(false); _options.SetEntity(grainState, entity); @@ -97,7 +97,7 @@ namespace Pole.Orleans.Provider.EntityframeworkCore try { - if (entity.DomainEvents.Count != 0) + if (entity.DomainEvents!=null&&entity.DomainEvents.Count != 0) { using (var unitOfWork = scope.ServiceProvider.GetRequiredService()) { diff --git a/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorageOptions.cs b/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorageOptions.cs index ccd8a42..d771806 100644 --- a/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorageOptions.cs +++ b/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStorageOptions.cs @@ -40,6 +40,8 @@ namespace Pole.Orleans.Provider.EntityframeworkCore { internal Func> DbSetAccessor { get; set; } + internal Func> DbSetNoTrackingAccessor { get; set; } + internal Func IsPersistedFunc { get; set; } internal Func GetETagFunc { get; set; } @@ -53,6 +55,7 @@ namespace Pole.Orleans.Provider.EntityframeworkCore public bool IsRelatedData { get; set; } internal Func> ReadStateAsync { get; set; } + internal Func> ReadStateNoTrackingAsync { get; set; } internal Action SetEntity { get; set; } diff --git a/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStoragePostConfigureOptions.cs b/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStoragePostConfigureOptions.cs index d68feba..87bf349 100644 --- a/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStoragePostConfigureOptions.cs +++ b/src/Pole.Orleans.Provider.EntityframeworkCore/GrainStoragePostConfigureOptions.cs @@ -69,6 +69,32 @@ namespace Pole.Orleans.Provider.EntityframeworkCore .CreateDefaultReadStateFunc(options); } } + if (options.ReadStateNoTrackingAsync == null) + { + if (options.DbSetNoTrackingAccessor == null) + options.DbSetNoTrackingAccessor = Convention?.CreateDefaultDbSetNoTrackingAccessorFunc() + ?? DefaultConvention.CreateDefaultDbSetNoTrackingAccessorFunc(); + + if (Convention != null) + Convention.SetDefaultKeySelector(options); + else + DefaultConvention.SetDefaultKeySelectors(options); + + if (options.PreCompileReadQuery) + { + options.ReadStateNoTrackingAsync + = Convention?.CreatePreCompiledDefaultReadStateNoTrackingFunc(options) + ?? DefaultConvention + .CreatePreCompiledDefaultReadStateNoTrackingFunc(options); + } + else + { + options.ReadStateNoTrackingAsync + = Convention?.CreateDefaultReadStateFunc() + ?? DefaultConvention + .CreateDefaultReadStateFunc(options); + } + } if (options.SetEntity == null) options.SetEntity = -- libgit2 0.25.0