From 8bd73e96e314c4326504035f895dc3873f29aeca Mon Sep 17 00:00:00 2001 From: Ali Yousefi Date: Fri, 17 Nov 2023 14:26:53 +0330 Subject: [PATCH] Support for UpdateBulkChangedValuesOnly and UpdateChangedValuesOnly --- .../AuthorizationRolePermissionsTests.cs | 1 - ...syMicroservices.Cores.AspCore.Tests.csproj | 6 +- .../Program.cs | 13 ++- .../Startup.cs | 13 ++- .../EasyMicroservices.Cores.AspCoreApi.csproj | 2 +- .../SimpleQueryServiceController.cs | 24 ++++++ ...ces.Cores.AspEntityFrameworkCoreApi.csproj | 2 +- .../StartUpExtensions.cs | 9 ++ .../UnitOfWork.cs | 37 ++++----- .../Requests/FilterRequestContract.cs | 4 + .../EasyMicroservices.Cores.Contracts.csproj | 2 +- .../Database/Interfaces/IWritableLogic.cs | 14 ++++ .../Database/Logics/DatabaseLogicBase.cs | 29 ++++++- .../Logics/DatabaseLogicInfrastructure.cs | 57 ++++++++++--- .../Logics/DatabaseMappedLogicBase.cs | 26 +++++- .../Logics/IdSchemaDatabaseMappedLogicBase.cs | 28 ++++++- .../EasyMicroservices.Cores.Database.csproj | 6 +- ...oservices.Cores.EntityFrameworkCore.csproj | 4 +- ...ores.Relational.EntityFrameworkCore.csproj | 4 +- .../LongIdMappedDatabaseLogicBaseTest.cs | 82 +++++++++++++++++-- .../EasyMicroservices.Cores.Tests.csproj | 2 +- 21 files changed, 302 insertions(+), 63 deletions(-) diff --git a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/AuthorizationRolePermissionsTests.cs b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/AuthorizationRolePermissionsTests.cs index 879045b..0dbf4ac 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/AuthorizationRolePermissionsTests.cs +++ b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/AuthorizationRolePermissionsTests.cs @@ -22,7 +22,6 @@ protected override void InitializeTestHost(bool isUseAuthorization, Action { services.AddScoped(); - services.AddScoped(service => service.GetService().GetUniqueIdentityManager()); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters diff --git a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/EasyMicroservices.Cores.AspCore.Tests.csproj b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/EasyMicroservices.Cores.AspCore.Tests.csproj index 5df1faf..3e0a8e5 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/EasyMicroservices.Cores.AspCore.Tests.csproj +++ b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/EasyMicroservices.Cores.AspCore.Tests.csproj @@ -10,8 +10,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -26,7 +26,7 @@ - 7.0.13 + 7.0.14 diff --git a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Program.cs b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Program.cs index f4a9ea6..4c80789 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Program.cs +++ b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Program.cs @@ -1,8 +1,11 @@ using EasyMicroservices.Cores.AspEntityFrameworkCoreApi; +using EasyMicroservices.Cores.Database.Interfaces; +using EasyMicroservices.Cores.Database.Managers; using EasyMicroservices.Cores.Relational.EntityFrameworkCore.Intrerfaces; using EasyMicroservices.Cores.Tests.DatabaseLogics.Database.Contexts; using EasyMicroservices.Cores.Tests.DatabaseLogics.Database.Entities; using Microsoft.EntityFrameworkCore; +using System.Text; namespace EasyMicroservices.Cores.AspCore.Tests { @@ -10,12 +13,20 @@ public class Program { public static async Task Main(string[] args) { + string microserviceName = "TestExample"; var app = StartUpExtensions.Create(args); app.Services.Builder(); app.Services.AddScoped((serviceProvider) => new UnitOfWork(serviceProvider).GetLongContractLogic()); app.Services.AddTransient(serviceProvider => new MyTestContext(serviceProvider.GetService())); app.Services.AddScoped(serviceProvider => new DatabaseBuilder()); - StartUpExtensions.AddWhiteLabel("TestExample", "RootAddresses:WhiteLabel"); + app.Services.AddSingleton((provider) => + { + if (UnitOfWork.DefaultUniqueIdentity.HasValue()) + return new DefaultUniqueIdentityManager(UnitOfWork.DefaultUniqueIdentity, UnitOfWork.MicroserviceId, microserviceName); + else + return new DefaultUniqueIdentityManager(UnitOfWork.MicroserviceId, microserviceName); + }); + StartUpExtensions.AddWhiteLabel(microserviceName, "RootAddresses:WhiteLabel"); var build = await app.Build(); build.MapControllers(); build.Run(); diff --git a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Startup.cs b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Startup.cs index e68bc82..7a1b0ef 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Startup.cs +++ b/src/CSharp/EasyMicroservices.Cores.AspCore.Tests/Startup.cs @@ -2,9 +2,12 @@ using EasyMicroservices.Cores.AspCoreApi.Interfaces; using EasyMicroservices.Cores.AspEntityFrameworkCoreApi; using EasyMicroservices.Cores.AspEntityFrameworkCoreApi.Interfaces; +using EasyMicroservices.Cores.Database.Interfaces; +using EasyMicroservices.Cores.Database.Managers; using EasyMicroservices.Cores.Relational.EntityFrameworkCore.Intrerfaces; using EasyMicroservices.Cores.Tests.DatabaseLogics.Database.Contexts; using EasyMicroservices.ServiceContracts; +using System.Text; namespace EasyMicroservices.Cores.AspCore.Tests { @@ -12,12 +15,20 @@ public class Startup { static WebApplicationBuilder CreateBuilder(long port) { + string microserviceName = "TestExample"; var app = StartUpExtensions.Create(null); app.Services.Builder(); app.Services.AddTransient((serviceProvider) => new UnitOfWork(serviceProvider)); app.Services.AddTransient(serviceProvider => new MyTestContext(serviceProvider.GetService())); app.Services.AddTransient(); - StartUpExtensions.AddWhiteLabelRoute("TestExample", $"http://localhost:6041"); + app.Services.AddSingleton((provider) => + { + if (UnitOfWork.DefaultUniqueIdentity.HasValue()) + return new DefaultUniqueIdentityManager(UnitOfWork.DefaultUniqueIdentity, UnitOfWork.MicroserviceId, microserviceName); + else + return new DefaultUniqueIdentityManager(UnitOfWork.MicroserviceId, microserviceName); + }); + StartUpExtensions.AddWhiteLabelRoute(microserviceName, $"http://localhost:6041"); app.Services.AddControllers().AddApplicationPart(typeof(UserController).Assembly); app.WebHost.UseUrls($"http://localhost:{port}"); return app; diff --git a/src/CSharp/EasyMicroservices.Cores.AspCoreApi/EasyMicroservices.Cores.AspCoreApi.csproj b/src/CSharp/EasyMicroservices.Cores.AspCoreApi/EasyMicroservices.Cores.AspCoreApi.csproj index 33b7efa..89a6da0 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspCoreApi/EasyMicroservices.Cores.AspCoreApi.csproj +++ b/src/CSharp/EasyMicroservices.Cores.AspCoreApi/EasyMicroservices.Cores.AspCoreApi.csproj @@ -5,7 +5,7 @@ AnyCPU;x64;x86 EasyMicroservices true - 0.0.0.47 + 0.0.0.48 asp core servces. EasyMicroservices@gmail.com core,cores,base,database,services,asp,aspnet diff --git a/src/CSharp/EasyMicroservices.Cores.AspCoreApi/SimpleQueryServiceController.cs b/src/CSharp/EasyMicroservices.Cores.AspCoreApi/SimpleQueryServiceController.cs index 8a6ea5d..520edfc 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspCoreApi/SimpleQueryServiceController.cs +++ b/src/CSharp/EasyMicroservices.Cores.AspCoreApi/SimpleQueryServiceController.cs @@ -89,6 +89,18 @@ public virtual Task> Update(TUpdateRequestCon return WritableContractLogic.Update(request, cancellationToken); } + /// + /// + /// + /// + /// + /// + [HttpPut] + public virtual Task> UpdateChangedValuesOnly(TUpdateRequestContract request, CancellationToken cancellationToken = default) + { + return WritableContractLogic.UpdateChangedValuesOnly(request, cancellationToken); + } + /// /// /// @@ -101,6 +113,18 @@ public virtual Task UpdateBulk(UpdateBulkRequestContract + /// + /// + /// + /// + /// + [HttpPut] + public virtual Task UpdateBulkChangedValuesOnly(UpdateBulkRequestContract request, CancellationToken cancellationToken = default) + { + return WritableContractLogic.UpdateBulk(request, cancellationToken); + } + /// /// /// diff --git a/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/EasyMicroservices.Cores.AspEntityFrameworkCoreApi.csproj b/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/EasyMicroservices.Cores.AspEntityFrameworkCoreApi.csproj index 22a99cf..57e990f 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/EasyMicroservices.Cores.AspEntityFrameworkCoreApi.csproj +++ b/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/EasyMicroservices.Cores.AspEntityFrameworkCoreApi.csproj @@ -5,7 +5,7 @@ AnyCPU;x64;x86 EasyMicroservices true - 0.0.0.47 + 0.0.0.48 asp core servces. EasyMicroservices@gmail.com core,cores,base,database,services,asp,aspnet,aspcore,efcore diff --git a/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/StartUpExtensions.cs b/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/StartUpExtensions.cs index fcdc8b8..c533e7c 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/StartUpExtensions.cs +++ b/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/StartUpExtensions.cs @@ -1,6 +1,8 @@ using EasyMicroservices.Cores.AspCoreApi.Authorizations; using EasyMicroservices.Cores.AspEntityFrameworkCoreApi.Interfaces; using EasyMicroservices.Cores.AspEntityFrameworkCoreApi.Middlewares; +using EasyMicroservices.Cores.Database.Interfaces; +using EasyMicroservices.Cores.Database.Managers; using EasyMicroservices.Cores.Interfaces; using EasyMicroservices.Cores.Relational.EntityFrameworkCore; using EasyMicroservices.Cores.Relational.EntityFrameworkCore.Builders; @@ -61,6 +63,13 @@ public static IServiceCollection Builder(this IServiceCollection servi services.AddHttpContextAccessor(); services.AddScoped(service => new UnitOfWork(service)); services.AddScoped(); + services.AddSingleton((provider) => + { + if (UnitOfWork.DefaultUniqueIdentity.HasValue()) + return new DefaultUniqueIdentityManager(UnitOfWork.DefaultUniqueIdentity, UnitOfWork.MicroserviceId, MicroserviceName); + else + return new DefaultUniqueIdentityManager(UnitOfWork.MicroserviceId, MicroserviceName); + }); services.AddScoped(service => new UnitOfWork(service).GetMapper()); services.AddTransient(serviceProvider => serviceProvider.GetService()); services.AddExceptionHandler((option) => diff --git a/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/UnitOfWork.cs b/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/UnitOfWork.cs index dbf49a8..3f2c330 100644 --- a/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/UnitOfWork.cs +++ b/src/CSharp/EasyMicroservices.Cores.AspEntityFrameworkCoreApi/UnitOfWork.cs @@ -34,7 +34,7 @@ public class UnitOfWork : IUnitOfWork /// /// /// - protected IServiceProvider _service; + protected IServiceProvider ServiceProvider { get; set; } /// /// /// @@ -42,7 +42,7 @@ public class UnitOfWork : IUnitOfWork public UnitOfWork(IServiceProvider service) { service.ThrowIfNull(nameof(service)); - _service = service; + ServiceProvider = service; } List Disposables { get; set; } = new List(); @@ -58,9 +58,9 @@ T AddDisposable(T data) /// public virtual IDatabase GetDatabase() { - if (_service == null) - throw new ObjectDisposedException(nameof(_service)); - var context = _service.GetService(); + if (ServiceProvider == null) + throw new ObjectDisposedException(nameof(ServiceProvider)); + var context = ServiceProvider.GetService(); if (context == null) throw new Exception("RelationalCoreContext is null, please add your context to RelationalCoreContext as Transit or Scope.\r\nExample : services.AddTransient(serviceProvider => serviceProvider.GetService());"); return AddDisposable(new EntityFrameworkCoreDatabaseProvider(context)); @@ -73,7 +73,7 @@ public virtual IDatabase GetDatabase() /// public virtual IAuthorization GetAuthorization() { - return _service.GetService(); + return ServiceProvider.GetService(); } /// /// @@ -84,9 +84,9 @@ public virtual IAuthorization GetAuthorization() public virtual IDatabase GetDatabase() where TContext : RelationalCoreContext { - if (_service == null) - throw new ObjectDisposedException(nameof(_service)); - var context = _service.GetService(); + if (ServiceProvider == null) + throw new ObjectDisposedException(nameof(ServiceProvider)); + var context = ServiceProvider.GetService(); if (context == null) throw new Exception("TContext is null, please add your context to Context as Transit or Scope.\r\nExample : services.AddTransient(serviceProvider => serviceProvider.GetService());"); @@ -347,14 +347,7 @@ public virtual void HandleDeserializationError(object sender, ErrorEventArgs err /// public virtual IUniqueIdentityManager GetUniqueIdentityManager() { - if (UniqueIdentityManager == null) - { - if (DefaultUniqueIdentity.HasValue()) - UniqueIdentityManager = new DefaultUniqueIdentityManager(DefaultUniqueIdentity, MicroserviceId, MicroserviceName); - else - UniqueIdentityManager = new DefaultUniqueIdentityManager(MicroserviceId, MicroserviceName); - } - return UniqueIdentityManager; + return ServiceProvider.GetService(); } /// @@ -366,9 +359,9 @@ public virtual IUniqueIdentityManager GetUniqueIdentityManager() /// public virtual Task Initialize(string microserviceName, string whiteLableRoute, params Type[] dbContextTypes) { - if (_service == null) - throw new ObjectDisposedException(nameof(_service)); - return new WhiteLabelManager(_service).Initialize(microserviceName, whiteLableRoute, dbContextTypes); + if (ServiceProvider == null) + throw new ObjectDisposedException(nameof(ServiceProvider)); + return new WhiteLabelManager(ServiceProvider).Initialize(microserviceName, whiteLableRoute, dbContextTypes); } IContractLogic GetInternalLongContractLogic() @@ -394,7 +387,7 @@ public virtual void Dispose() InternalSyncDispose(); _ = InternalDispsose(); Disposables.Clear(); - _service = null; + ServiceProvider = null; } /// @@ -406,7 +399,7 @@ public virtual async ValueTask DisposeAsync() InternalSyncDispose(); await InternalDispsose(); Disposables.Clear(); - _service = null; + ServiceProvider = null; } async Task InternalDispsose() diff --git a/src/CSharp/EasyMicroservices.Cores.Contracts/Contracts/Requests/FilterRequestContract.cs b/src/CSharp/EasyMicroservices.Cores.Contracts/Contracts/Requests/FilterRequestContract.cs index 53bb422..cee3c08 100644 --- a/src/CSharp/EasyMicroservices.Cores.Contracts/Contracts/Requests/FilterRequestContract.cs +++ b/src/CSharp/EasyMicroservices.Cores.Contracts/Contracts/Requests/FilterRequestContract.cs @@ -66,5 +66,9 @@ public class FilterRequestContract /// text to search /// public string Text { get; set; } + /// + /// en-US, fa-IR + /// + public string Language { get; set; } } } diff --git a/src/CSharp/EasyMicroservices.Cores.Contracts/EasyMicroservices.Cores.Contracts.csproj b/src/CSharp/EasyMicroservices.Cores.Contracts/EasyMicroservices.Cores.Contracts.csproj index be30312..663d64b 100644 --- a/src/CSharp/EasyMicroservices.Cores.Contracts/EasyMicroservices.Cores.Contracts.csproj +++ b/src/CSharp/EasyMicroservices.Cores.Contracts/EasyMicroservices.Cores.Contracts.csproj @@ -5,7 +5,7 @@ AnyCPU;x64;x86 EasyMicroservices true - 0.0.0.47 + 0.0.0.48 core contracts. EasyMicroservices@gmail.com core,cores,base,contract,contracts,dto,dtos diff --git a/src/CSharp/EasyMicroservices.Cores.Database/Database/Interfaces/IWritableLogic.cs b/src/CSharp/EasyMicroservices.Cores.Database/Database/Interfaces/IWritableLogic.cs index d430986..a9476f6 100644 --- a/src/CSharp/EasyMicroservices.Cores.Database/Database/Interfaces/IWritableLogic.cs +++ b/src/CSharp/EasyMicroservices.Cores.Database/Database/Interfaces/IWritableLogic.cs @@ -25,10 +25,24 @@ public interface IWritableLogic /// /// /// + Task> UpdateChangedValuesOnly(TRequsetSchema schema, CancellationToken cancellationToken = default); + /// + /// + /// + /// + /// + /// Task UpdateBulk(UpdateBulkRequestContract schema, CancellationToken cancellationToken = default); /// /// /// + /// + /// + /// + Task UpdateBulkChangedValuesOnly(UpdateBulkRequestContract schema, CancellationToken cancellationToken = default); + /// + /// + /// /// /// /// diff --git a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicBase.cs b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicBase.cs index a15c550..4baf009 100644 --- a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicBase.cs +++ b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicBase.cs @@ -5,7 +5,6 @@ using EasyMicroservices.Mapper.Interfaces; using EasyMicroservices.ServiceContracts; using System; -using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; @@ -158,7 +157,19 @@ public async Task> GetBy(Expression /// public Task> Update(TEntity entity, CancellationToken cancellationToken = default) { - return Update(_easyWriteableQueryable, entity, cancellationToken); + return Update(_easyWriteableQueryable, entity, false, cancellationToken); + } + + /// + /// + /// + /// + /// + /// + /// + public Task> UpdateChangedValuesOnly(TEntity entity, CancellationToken cancellationToken = default) + { + return Update(_easyWriteableQueryable, entity, true, cancellationToken); } /// @@ -170,7 +181,19 @@ public Task> Update(TEntity entity, CancellationToken c /// public Task UpdateBulk(UpdateBulkRequestContract request, CancellationToken cancellationToken = default) { - return UpdateBulk(_easyWriteableQueryable, request, cancellationToken); + return UpdateBulk(_easyWriteableQueryable, request, false, cancellationToken); + } + + /// + /// + /// + /// + /// + /// + /// + public Task UpdateBulkChangedValuesOnly(UpdateBulkRequestContract request, CancellationToken cancellationToken = default) + { + return UpdateBulk(_easyWriteableQueryable, request, true, cancellationToken); } /// diff --git a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicInfrastructure.cs b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicInfrastructure.cs index abf4b69..e42767a 100644 --- a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicInfrastructure.cs +++ b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseLogicInfrastructure.cs @@ -412,30 +412,33 @@ public async Task> GetAllByUniqueIdentity /// /// + /// /// /// - public Task> Update(IEasyWritableQueryableAsync easyWritableQueryable, TEntity entity, CancellationToken cancellationToken = default) + public Task> Update(IEasyWritableQueryableAsync easyWritableQueryable, TEntity entity, bool updateOnlyChangedValue, CancellationToken cancellationToken = default) where TEntity : class { - return InternalUpdate(easyWritableQueryable, entity, cancellationToken, false, true); + return InternalUpdate(easyWritableQueryable, entity, updateOnlyChangedValue, false, true, cancellationToken); } - private async Task> InternalUpdate(IEasyWritableQueryableAsync easyWritableQueryable, TEntity entity, CancellationToken cancellationToken = default, bool doSkipUpdate = true, bool doSkipDelete = true) + private async Task> InternalUpdate(IEasyWritableQueryableAsync easyWritableQueryable, TEntity entity, bool updateOnlyChangedValue, bool doSkipUpdate = true, bool doSkipDelete = true, CancellationToken cancellationToken = default) where TEntity : class { - var result = await InternalUpdateBulk(easyWritableQueryable, new List() { entity }, cancellationToken, doSkipUpdate, doSkipDelete); + var result = await InternalUpdateBulk(easyWritableQueryable, new List() { entity }, updateOnlyChangedValue, doSkipUpdate, doSkipDelete, cancellationToken); if (!result) return result.ToContract(); return result.Result.First(); } - private async Task> InternalUpdateBulk(IEasyWritableQueryableAsync easyWritableQueryable, List entities, CancellationToken cancellationToken = default, bool doSkipUpdate = true, bool doSkipDelete = true) + private async Task> InternalUpdateBulk(IEasyWritableQueryableAsync easyWritableQueryable, List entities, bool updateOnlyChangedValue, bool doSkipUpdate = true, bool doSkipDelete = true, CancellationToken cancellationToken = default) where TEntity : class { List> items = new List>(); var result = await easyWritableQueryable.UpdateBulkAsync(entities, cancellationToken); foreach (var entity in result) { + if (updateOnlyChangedValue) + UpdateOnlyChangedValue(easyWritableQueryable.Context, entity.Entity); if (entity.Entity is IDateTimeSchema schema) { easyWritableQueryable.Context.ChangeModificationPropertyState(entity.Entity, nameof(IDateTimeSchema.CreationDateTime), false); @@ -455,6 +458,34 @@ private async Task> InternalUpdateBulk(IEa return items.Select(x => x.Entity).ToList(); } + void UpdateOnlyChangedValue(IContext context, TEntity entity) + where TEntity : class + { + var properties = context.GetProperties(entity); + foreach (var property in properties) + { + if (property.IsModified) + { + if (property.CurrentValue is null && property.CurrentValue == GetDefault(property.Metadata.ClrType)) + property.IsModified = false; + else if (property.CurrentValue.Equals(GetDefault(property.Metadata.ClrType))) + property.IsModified = false; + } + } + } + + static object GetDefault(Type type) + { + return typeof(DatabaseLogicInfrastructure) + .GetMethod(nameof(GetDefaultValueGeneric), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) + .MakeGenericMethod(type).Invoke(null,null); + } + + static T GetDefaultValueGeneric() + { + return default(T); + } + /// /// /// @@ -463,13 +494,14 @@ private async Task> InternalUpdateBulk(IEa /// /// /// + /// /// /// - public async Task> Update(IEasyWritableQueryableAsync easyWritableQueryable, TUpdateContract contract, CancellationToken cancellationToken = default) + public async Task> Update(IEasyWritableQueryableAsync easyWritableQueryable, TUpdateContract contract, bool updateOnlyChangedValue, CancellationToken cancellationToken = default) where TEntity : class { var entity = await MapAsync(contract); - var result = await Update(easyWritableQueryable, entity, cancellationToken); + var result = await Update(easyWritableQueryable, entity, updateOnlyChangedValue, cancellationToken); if (!result) return result.ToContract(); var mappedResult = await MapAsync(result.Result); @@ -483,13 +515,14 @@ public async Task> Update /// /// + /// /// /// - public async Task UpdateBulk(IEasyWritableQueryableAsync easyWritableQueryable, UpdateBulkRequestContract request, CancellationToken cancellationToken = default) + public async Task UpdateBulk(IEasyWritableQueryableAsync easyWritableQueryable, UpdateBulkRequestContract request, bool updateOnlyChangedValue, CancellationToken cancellationToken = default) where TEntity : class { var entities = await MapToListAsync(request.Items); - var result = await InternalUpdateBulk(easyWritableQueryable, entities, cancellationToken, false, true); + var result = await InternalUpdateBulk(easyWritableQueryable, entities, updateOnlyChangedValue, false, true, cancellationToken); return result; } #endregion @@ -653,7 +686,7 @@ public async Task SoftDeleteBy(IEasyReadableQueryableA else return (FailedReasonType.OperationFailed, $"Your entity type {item.GetType().FullName} is not inheritance from ISoftDeleteSchema"); } - return await InternalUpdateBulk(easyWritableQueryable, getResult.Result, cancellationToken, true, false); + return await InternalUpdateBulk(easyWritableQueryable, getResult.Result, false, true, false, cancellationToken); } #endregion @@ -678,7 +711,7 @@ public async Task> Add(IEasyWritableQueryableA await easyWritableQueryable.SaveChangesAsync(); if (_uniqueIdentityManager.UpdateUniqueIdentity(easyWritableQueryable.Context, result.Entity)) { - await InternalUpdate(easyWritableQueryable, result.Entity, cancellationToken); + await InternalUpdate(easyWritableQueryable, result.Entity, false, true, true, cancellationToken); await easyWritableQueryable.SaveChangesAsync(); } return result.Entity; @@ -713,7 +746,7 @@ public async Task AddBulk(IEasyWritableQueryableAsync< } if (anyUpdate) { - await InternalUpdateBulk(easyWritableQueryable, result.Select(x => x.Entity).ToList(), cancellationToken); + await InternalUpdateBulk(easyWritableQueryable, result.Select(x => x.Entity).ToList(), false, true, true, cancellationToken); await easyWritableQueryable.SaveChangesAsync(); } return true; diff --git a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseMappedLogicBase.cs b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseMappedLogicBase.cs index a40539e..e8dcb02 100644 --- a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseMappedLogicBase.cs +++ b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/DatabaseMappedLogicBase.cs @@ -235,7 +235,18 @@ public Task SoftDeleteBy(Expression> predic /// public Task> Update(TUpdateRequestContract schema, CancellationToken cancellationToken = default) { - return Update(_easyWriteableQueryable, schema, cancellationToken); + return Update(_easyWriteableQueryable, schema, false, cancellationToken); + } + + /// + /// + /// + /// + /// + /// + public Task> UpdateChangedValuesOnly(TUpdateRequestContract schema, CancellationToken cancellationToken = default) + { + return Update(_easyWriteableQueryable, schema, true, cancellationToken); } /// @@ -247,7 +258,18 @@ public Task> Update(TUpdateRequestContract sc /// public Task UpdateBulk(UpdateBulkRequestContract schema, CancellationToken cancellationToken = default) { - return UpdateBulk(_easyWriteableQueryable, schema, cancellationToken); + return UpdateBulk(_easyWriteableQueryable, schema, false, cancellationToken); + } + + /// + /// + /// + /// + /// + /// + public Task UpdateBulkChangedValuesOnly(UpdateBulkRequestContract schema, CancellationToken cancellationToken = default) + { + return UpdateBulk(_easyWriteableQueryable, schema, true, cancellationToken); } /// diff --git a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/IdSchemaDatabaseMappedLogicBase.cs b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/IdSchemaDatabaseMappedLogicBase.cs index 03cedea..3025dec 100644 --- a/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/IdSchemaDatabaseMappedLogicBase.cs +++ b/src/CSharp/EasyMicroservices.Cores.Database/Database/Logics/IdSchemaDatabaseMappedLogicBase.cs @@ -218,8 +218,20 @@ public Task HardDeleteBy(Expression> predic /// public Task> Update(TUpdateRequestContract schema, CancellationToken cancellationToken = default) { - return Update(_easyWriteableQueryable, schema, cancellationToken); + return Update(_easyWriteableQueryable, schema, false, cancellationToken); } + + /// + /// + /// + /// + /// + /// + public Task> UpdateChangedValuesOnly(TUpdateRequestContract schema, CancellationToken cancellationToken = default) + { + return Update(_easyWriteableQueryable, schema, true, cancellationToken); + } + /// /// /// @@ -229,7 +241,19 @@ public Task> Update(TUpdateRequestContract sc /// public Task UpdateBulk(UpdateBulkRequestContract schema, CancellationToken cancellationToken = default) { - return UpdateBulk(_easyWriteableQueryable, schema, cancellationToken); + return UpdateBulk(_easyWriteableQueryable, schema, false, cancellationToken); + } + + /// + /// + /// + /// + /// + /// + /// + public Task UpdateBulkChangedValuesOnly(UpdateBulkRequestContract schema, CancellationToken cancellationToken = default) + { + return UpdateBulk(_easyWriteableQueryable, schema, true, cancellationToken); } /// diff --git a/src/CSharp/EasyMicroservices.Cores.Database/EasyMicroservices.Cores.Database.csproj b/src/CSharp/EasyMicroservices.Cores.Database/EasyMicroservices.Cores.Database.csproj index 4b3176e..c8e0832 100644 --- a/src/CSharp/EasyMicroservices.Cores.Database/EasyMicroservices.Cores.Database.csproj +++ b/src/CSharp/EasyMicroservices.Cores.Database/EasyMicroservices.Cores.Database.csproj @@ -5,7 +5,7 @@ AnyCPU;x64;x86 EasyMicroservices true - 0.0.0.47 + 0.0.0.48 core of database. EasyMicroservices@gmail.com core,cores,base,database @@ -18,9 +18,9 @@ - + - + diff --git a/src/CSharp/EasyMicroservices.Cores.EntityFrameworkCore/EasyMicroservices.Cores.EntityFrameworkCore.csproj b/src/CSharp/EasyMicroservices.Cores.EntityFrameworkCore/EasyMicroservices.Cores.EntityFrameworkCore.csproj index c096adc..2953829 100644 --- a/src/CSharp/EasyMicroservices.Cores.EntityFrameworkCore/EasyMicroservices.Cores.EntityFrameworkCore.csproj +++ b/src/CSharp/EasyMicroservices.Cores.EntityFrameworkCore/EasyMicroservices.Cores.EntityFrameworkCore.csproj @@ -5,7 +5,7 @@ AnyCPU;x64;x86 EasyMicroservices true - 0.0.0.47 + 0.0.0.48 ef core of database. EasyMicroservices@gmail.com core,cores,base,database,ef,efcore @@ -17,7 +17,7 @@ - + diff --git a/src/CSharp/EasyMicroservices.Cores.Relational.EntityFrameworkCore/EasyMicroservices.Cores.Relational.EntityFrameworkCore.csproj b/src/CSharp/EasyMicroservices.Cores.Relational.EntityFrameworkCore/EasyMicroservices.Cores.Relational.EntityFrameworkCore.csproj index b8f1205..2c0fb67 100644 --- a/src/CSharp/EasyMicroservices.Cores.Relational.EntityFrameworkCore/EasyMicroservices.Cores.Relational.EntityFrameworkCore.csproj +++ b/src/CSharp/EasyMicroservices.Cores.Relational.EntityFrameworkCore/EasyMicroservices.Cores.Relational.EntityFrameworkCore.csproj @@ -5,7 +5,7 @@ AnyCPU;x64;x86 EasyMicroservices true - 0.0.0.47 + 0.0.0.48 ef core of Relational database. EasyMicroservices@gmail.com core,cores,base,database,ef,efcore,Relational @@ -21,7 +21,7 @@ - + diff --git a/src/CSharp/EasyMicroservices.Cores.Tests/DatabaseLogics/LongIdMappedDatabaseLogicBaseTest.cs b/src/CSharp/EasyMicroservices.Cores.Tests/DatabaseLogics/LongIdMappedDatabaseLogicBaseTest.cs index f1f8c1f..e16d700 100644 --- a/src/CSharp/EasyMicroservices.Cores.Tests/DatabaseLogics/LongIdMappedDatabaseLogicBaseTest.cs +++ b/src/CSharp/EasyMicroservices.Cores.Tests/DatabaseLogics/LongIdMappedDatabaseLogicBaseTest.cs @@ -164,12 +164,12 @@ public async Task UpdateAsync(string userName, string toUserName) { await using var logic = GetUpdateContractLogic(); var added = await AddAsync(userName); - added.UserName = toUserName; + added.UserName = toUserName + "1"; var updateResult = await logic.Update(new UpdateUserContract() { Id = added.Id, UniqueIdentity = added.UniqueIdentity, - UserName = added.UserName + UserName = toUserName }); Assert.NotNull(updateResult.Result.ModificationDateTime); Assert.Equal(updateResult.Result.CreationDateTime, added.CreationDateTime); @@ -187,9 +187,37 @@ public async Task UpdateAsync(string userName, string toUserName) } [Theory] - [InlineData("Mahdi", "Mahdi1")] - [InlineData("Hassan", "Hassan1")] - public async Task UpdateBulkAsync(string userName, string toUserName) + [InlineData("Mahdi")] + [InlineData("Hassan")] + public async Task UpdateChangedValuesOnlyAsync(string userName) + { + await using var logic = GetUpdateContractLogic(); + var added = await AddAsync(userName); + var updateResult = await logic.UpdateChangedValuesOnly(new UpdateUserContract() + { + Id = added.Id, + UniqueIdentity = added.UniqueIdentity, + UserName = default + }); + Assert.NotNull(updateResult.Result.ModificationDateTime); + Assert.Equal(updateResult.Result.CreationDateTime, added.CreationDateTime); + Assert.True(updateResult.Result.CreationDateTime > DateTime.Now.AddMinutes(-5)); + Assert.True(updateResult.Result.ModificationDateTime > DateTime.Now.AddMinutes(-5)); + var found = await logic.GetById(new GetIdRequestContract() + { + Id = added.Id + }); + Assert.NotNull(found.Result.ModificationDateTime); + Assert.Equal(found.Result.CreationDateTime, added.CreationDateTime); + Assert.True(found.Result.CreationDateTime > DateTime.Now.AddMinutes(-5)); + Assert.True(found.Result.ModificationDateTime > DateTime.Now.AddMinutes(-5)); + Assert.Equal(found.Result.UserName, userName); + } + + [Theory] + [InlineData("Mahdi")] + [InlineData("Hassan")] + public async Task UpdateBulkAsync(string userName) { await using var logic = GetContractLogic(); List items = new List(); @@ -230,6 +258,50 @@ public async Task UpdateBulkAsync(string userName, string toUserName) } } + [Theory] + [InlineData("Mahdi")] + [InlineData("Hassan")] + public async Task UpdateBulkChangedValuesOnlyAsync(string userName) + { + await using var logic = GetContractLogic(); + List items = new List(); + for (int i = 0; i < 10; i++) + { + items.Add(new UserEntity() + { + UserName = userName + Guid.NewGuid() + }); + } + var user = await logic.AddBulk(items); + Assert.True(user.IsSuccess); + List updateItems = new List(); + foreach (var item in items) + { + var foundUser = await logic.GetBy(x => x.UserName == item.UserName); + Assert.True(foundUser.IsSuccess); + Assert.True(foundUser.Result.CreationDateTime > DateTime.Now.AddMinutes(-5)); + Assert.True(items.Any(x => x.UserName == item.UserName)); + updateItems.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(Newtonsoft.Json.JsonConvert.SerializeObject(foundUser.Result))); + } + foreach (var item in updateItems) + { + item.UserName = default; + } + await using var logic2 = GetContractLogic(); + var updateResult = await logic2.UpdateBulkChangedValuesOnly(updateItems); + foreach (var item in updateItems) + { + var found = await logic2.GetBy(x => x.UserName == item.UserName); + Assert.True(found); + Assert.NotNull(found.Result.ModificationDateTime); + Assert.Equal(found.Result.CreationDateTime, item.CreationDateTime); + Assert.True(found.Result.CreationDateTime > DateTime.Now.AddMinutes(-5)); + Assert.True(found.Result.ModificationDateTime > DateTime.Now.AddMinutes(-5)); + var find = items.FirstOrDefault(x => x.UserName == found.Result.UserName); + Assert.Equal(found.Result.UserName, find.UserName); + } + } + [Theory] [InlineData("Ahmad")] [InlineData("Yasin")] diff --git a/src/CSharp/EasyMicroservices.Cores.Tests/EasyMicroservices.Cores.Tests.csproj b/src/CSharp/EasyMicroservices.Cores.Tests/EasyMicroservices.Cores.Tests.csproj index a2ccdb3..5114fbb 100644 --- a/src/CSharp/EasyMicroservices.Cores.Tests/EasyMicroservices.Cores.Tests.csproj +++ b/src/CSharp/EasyMicroservices.Cores.Tests/EasyMicroservices.Cores.Tests.csproj @@ -14,7 +14,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive