From 2150e725f25088027d66b9bfea2fb3140a86cda8 Mon Sep 17 00:00:00 2001 From: Andrei Kolchanov Date: Tue, 5 Apr 2022 20:30:38 +0500 Subject: [PATCH] DL-60: Refactor basic logic into basic crud/search services --- .../Services/Crud/Basic/BasicPriceService.cs | 108 ++++++++++++ .../Basic/BasicPricelistAssignmentService.cs | 56 ++++++ .../Crud/Basic/BasicPricelistService.cs | 30 ++++ .../Services/Crud/PriceService.cs | 90 +--------- .../Crud/PricelistAssignmentService.cs | 34 +--- .../Services/Crud/PricelistService.cs | 12 +- .../Search/Basic/BasicPriceSearchService.cs | 159 ++++++++++++++++++ .../BasicPricelistAssignmentSearchService.cs | 68 ++++++++ .../Basic/BasicPricelistSearchService.cs | 62 +++++++ .../Services/Search/PriceSearchService.cs | 144 +--------------- .../PricelistAssignmentSearchService.cs | 47 +----- .../Services/Search/PricelistSearchService.cs | 46 +---- 12 files changed, 498 insertions(+), 358 deletions(-) create mode 100644 src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPriceService.cs create mode 100644 src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistAssignmentService.cs create mode 100644 src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistService.cs create mode 100644 src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPriceSearchService.cs create mode 100644 src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistAssignmentSearchService.cs create mode 100644 src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistSearchService.cs diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPriceService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPriceService.cs new file mode 100644 index 00000000..42f8dea1 --- /dev/null +++ b/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPriceService.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using VirtoCommerce.Platform.Caching; +using VirtoCommerce.Platform.Core.Caching; +using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.Events; +using VirtoCommerce.Platform.Core.GenericCrud; +using VirtoCommerce.Platform.Data.GenericCrud; +using VirtoCommerce.PricingModule.Core.Model; +using VirtoCommerce.PricingModule.Data.Model; +using VirtoCommerce.PricingModule.Data.Repositories; + +namespace VirtoCommerce.PricingModule.Data.Services.Crud.Basic +{ + public class BasicPriceService : CrudService + where TModel : Price + where TEntity : PriceEntity, Platform.Core.Domain.IDataEntity + where TChangeEvent : GenericChangedEntryEvent + where TChangedEvent : GenericChangedEntryEvent + where TPriceListModel : Pricelist + { + private readonly ICrudService _pricelistService; + public BasicPriceService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, IEventPublisher eventPublisher, ICrudService pricelistService) + : base(repositoryFactory, platformMemoryCache, eventPublisher) + { + _pricelistService = pricelistService; + } + + public override async Task SaveChangesAsync(IEnumerable models) + { + var pkMap = new PrimaryKeyResolvingMap(); + var changedEntries = new List>(); + using (var repository = _repositoryFactory()) + { + var alreadyExistPricesEntities = await LoadEntities(repository, models.Select(x => x.Id).Where(x => x != null).Distinct().ToList()); + + //Create default priceLists for prices without pricelist + foreach (var priceWithoutPricelistGroup in models.Where(x => x.PricelistId == null).GroupBy(x => x.Currency)) + { + var defaultPriceListId = GetDefaultPriceListName(priceWithoutPricelistGroup.Key); + var pricelists = await _pricelistService.GetAsync(new List { defaultPriceListId }); + if (pricelists.IsNullOrEmpty()) + { + repository.Add(AbstractTypeFactory.TryCreateInstance().FromModel(GetDefaultPriceList(priceWithoutPricelistGroup, defaultPriceListId), pkMap)); + } + foreach (var priceWithoutPricelist in priceWithoutPricelistGroup) + { + priceWithoutPricelist.PricelistId = defaultPriceListId; + } + } + + foreach (var price in models) + { + var sourceEntity = AbstractTypeFactory.TryCreateInstance().FromModel(price, pkMap); + var targetEntity = alreadyExistPricesEntities.FirstOrDefault(x => x.Id == price.Id); + if (targetEntity != null) + { + changedEntries.Add(new GenericChangedEntry(price, (TModel)targetEntity.ToModel(AbstractTypeFactory.TryCreateInstance()), EntryState.Modified)); + sourceEntity.Patch(targetEntity); + } + else + { + changedEntries.Add(new GenericChangedEntry(price, EntryState.Added)); + repository.Add(sourceEntity); + } + } + + await _eventPublisher.Publish(EventFactory(changedEntries)); + + await repository.UnitOfWork.CommitAsync(); + pkMap.ResolvePrimaryKeys(); + + ClearCache(models); + + await _eventPublisher.Publish(EventFactory(changedEntries)); + } + } + + protected override async Task> LoadEntities(IRepository repository, IEnumerable ids, string responseGroup) + { + return (IEnumerable)await ((IPricingRepository)repository).GetPricesByIdsAsync(ids); + } + + protected override void ClearCache(IEnumerable models) + { + GenericCachingRegion.ExpireRegion(); + base.ClearCache(models); + } + + protected virtual Pricelist GetDefaultPriceList(IGrouping priceWithoutPricelistGroup, string defaultPriceListId) + { + var defaultPriceList = AbstractTypeFactory.TryCreateInstance(); + defaultPriceList.Id = defaultPriceListId; + defaultPriceList.Currency = priceWithoutPricelistGroup.Key; + defaultPriceList.Name = defaultPriceListId; + defaultPriceList.Description = defaultPriceListId; + return defaultPriceList; + } + private string GetDefaultPriceListName(string currency) + { + var result = "Default" + currency; + return result; + } + + } +} diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistAssignmentService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistAssignmentService.cs new file mode 100644 index 00000000..a77a10b8 --- /dev/null +++ b/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistAssignmentService.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using FluentValidation; +using VirtoCommerce.Platform.Caching; +using VirtoCommerce.Platform.Core.Caching; +using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.Events; +using VirtoCommerce.Platform.Data.GenericCrud; +using VirtoCommerce.PricingModule.Core.Model; +using VirtoCommerce.PricingModule.Data.Model; +using VirtoCommerce.PricingModule.Data.Repositories; + +namespace VirtoCommerce.PricingModule.Data.Services.Crud.Basic +{ + public class BasicPricelistAssignmentService : CrudService + where TModel : PricelistAssignment + where TEntity : PricelistAssignmentEntity, Platform.Core.Domain.IDataEntity + where TChangeEvent : GenericChangedEntryEvent + where TChangedEvent : GenericChangedEntryEvent + { + private readonly AbstractValidator> _validator; + + public BasicPricelistAssignmentService(Func repositoryFactory, + IPlatformMemoryCache platformMemoryCache, + IEventPublisher eventPublisher, + AbstractValidator> validator) + : base(repositoryFactory, platformMemoryCache, eventPublisher) + { + _validator = validator; + } + + protected override async Task> LoadEntities(IRepository repository, IEnumerable ids, string responseGroup) + { + return (IEnumerable)await ((IPricingRepository)repository).GetPricelistAssignmentsByIdAsync(ids); + } + + protected override Task BeforeSaveChanges(IEnumerable models) + { + _validator.ValidateAndThrow(models); + + return base.BeforeSaveChanges(models); + } + + protected override void ClearCache(IEnumerable models) + { + foreach (var assignment in models) + { + GenericCachingRegion.ExpireTokenForKey(assignment.Id); + GenericCachingRegion.ExpireTokenForKey(assignment.PricelistId); + } + GenericSearchCachingRegion.ExpireRegion(); + GenericCachingRegion.ExpireRegion(); + } + } +} diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistService.cs new file mode 100644 index 00000000..a3b66173 --- /dev/null +++ b/src/VirtoCommerce.PricingModule.Data/Services/Crud/Basic/BasicPricelistService.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using VirtoCommerce.Platform.Core.Caching; +using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.Events; +using VirtoCommerce.Platform.Data.GenericCrud; +using VirtoCommerce.PricingModule.Core.Model; +using VirtoCommerce.PricingModule.Data.Model; +using VirtoCommerce.PricingModule.Data.Repositories; + +namespace VirtoCommerce.PricingModule.Data.Services.Crud.Basic +{ + public class BasicPricelistService : CrudService + where TModel : Pricelist + where TEntity : PricelistEntity, Platform.Core.Domain.IDataEntity + where TChangeEvent : GenericChangedEntryEvent + where TChangedEvent : GenericChangedEntryEvent + { + public BasicPricelistService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, IEventPublisher eventPublisher) + : base(repositoryFactory, platformMemoryCache, eventPublisher) + { + } + + protected override async Task> LoadEntities(IRepository repository, IEnumerable ids, string responseGroup) + { + return (IEnumerable)await ((IPricingRepository)repository).GetPricelistByIdsAsync(ids, responseGroup); + } + } +} diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Crud/PriceService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Crud/PriceService.cs index 422d316a..8752a039 100644 --- a/src/VirtoCommerce.PricingModule.Data/Services/Crud/PriceService.cs +++ b/src/VirtoCommerce.PricingModule.Data/Services/Crud/PriceService.cs @@ -1,104 +1,20 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using VirtoCommerce.Platform.Caching; using VirtoCommerce.Platform.Core.Caching; -using VirtoCommerce.Platform.Core.Common; using VirtoCommerce.Platform.Core.Events; using VirtoCommerce.Platform.Core.GenericCrud; -using VirtoCommerce.Platform.Data.GenericCrud; using VirtoCommerce.PricingModule.Core.Events; using VirtoCommerce.PricingModule.Core.Model; using VirtoCommerce.PricingModule.Data.Model; using VirtoCommerce.PricingModule.Data.Repositories; +using VirtoCommerce.PricingModule.Data.Services.Crud.Basic; namespace VirtoCommerce.PricingModule.Data.Services { - public class PriceService : CrudService + public class PriceService : BasicPriceService { - private readonly ICrudService _pricelistService; public PriceService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, IEventPublisher eventPublisher, ICrudService pricelistService) - : base(repositoryFactory, platformMemoryCache, eventPublisher) + : base(repositoryFactory, platformMemoryCache, eventPublisher, pricelistService) { - _pricelistService = pricelistService; - } - - - public override async Task SaveChangesAsync(IEnumerable models) - { - var pkMap = new PrimaryKeyResolvingMap(); - var changedEntries = new List>(); - using (var repository = _repositoryFactory()) - { - var alreadyExistPricesEntities = await LoadEntities(repository, models.Select(x => x.Id).Where(x => x != null).Distinct().ToList()); - - //Create default priceLists for prices without pricelist - foreach (var priceWithoutPricelistGroup in models.Where(x => x.PricelistId == null).GroupBy(x => x.Currency)) - { - var defaultPriceListId = GetDefaultPriceListName(priceWithoutPricelistGroup.Key); - var pricelists = await _pricelistService.GetByIdsAsync(new[] { defaultPriceListId }); - if (pricelists.IsNullOrEmpty()) - { - repository.Add(AbstractTypeFactory.TryCreateInstance().FromModel(GetDefaultPriceList(priceWithoutPricelistGroup, defaultPriceListId), pkMap)); - } - foreach (var priceWithoutPricelist in priceWithoutPricelistGroup) - { - priceWithoutPricelist.PricelistId = defaultPriceListId; - } - } - - foreach (var price in models) - { - var sourceEntity = AbstractTypeFactory.TryCreateInstance().FromModel(price, pkMap); - var targetEntity = alreadyExistPricesEntities.FirstOrDefault(x => x.Id == price.Id); - if (targetEntity != null) - { - changedEntries.Add(new GenericChangedEntry(price, targetEntity.ToModel(AbstractTypeFactory.TryCreateInstance()), EntryState.Modified)); - sourceEntity.Patch(targetEntity); - } - else - { - changedEntries.Add(new GenericChangedEntry(price, EntryState.Added)); - repository.Add(sourceEntity); - } - } - - await _eventPublisher.Publish(new PriceChangingEvent(changedEntries)); - - await repository.UnitOfWork.CommitAsync(); - pkMap.ResolvePrimaryKeys(); - - ClearCache(models); - - await _eventPublisher.Publish(new PriceChangedEvent(changedEntries)); - } - } - - protected override async Task> LoadEntities(IRepository repository, IEnumerable ids, string responseGroup) - { - return await ((IPricingRepository)repository).GetPricesByIdsAsync(ids); - } - - protected override void ClearCache(IEnumerable models) - { - GenericCachingRegion.ExpireRegion(); - base.ClearCache(models); - } - - protected virtual Pricelist GetDefaultPriceList(IGrouping priceWithoutPricelistGroup, string defaultPriceListId) - { - var defaultPriceList = AbstractTypeFactory.TryCreateInstance(); - defaultPriceList.Id = defaultPriceListId; - defaultPriceList.Currency = priceWithoutPricelistGroup.Key; - defaultPriceList.Name = defaultPriceListId; - defaultPriceList.Description = defaultPriceListId; - return defaultPriceList; - } - private string GetDefaultPriceListName(string currency) - { - var result = "Default" + currency; - return result; } } } diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistAssignmentService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistAssignmentService.cs index 66d7ee79..03d822da 100644 --- a/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistAssignmentService.cs +++ b/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistAssignmentService.cs @@ -1,53 +1,25 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using FluentValidation; -using VirtoCommerce.Platform.Caching; using VirtoCommerce.Platform.Core.Caching; -using VirtoCommerce.Platform.Core.Common; using VirtoCommerce.Platform.Core.Events; -using VirtoCommerce.Platform.Data.GenericCrud; using VirtoCommerce.PricingModule.Core.Events; using VirtoCommerce.PricingModule.Core.Model; using VirtoCommerce.PricingModule.Data.Model; using VirtoCommerce.PricingModule.Data.Repositories; +using VirtoCommerce.PricingModule.Data.Services.Crud.Basic; namespace VirtoCommerce.PricingModule.Data.Services { - public class PricelistAssignmentService : CrudService + public class PricelistAssignmentService : BasicPricelistAssignmentService { - private readonly AbstractValidator> _validator; public PricelistAssignmentService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, IEventPublisher eventPublisher, AbstractValidator> validator) - : base(repositoryFactory, platformMemoryCache, eventPublisher) + : base(repositoryFactory, platformMemoryCache, eventPublisher, validator) { - _validator = validator; - } - - protected override async Task> LoadEntities(IRepository repository, IEnumerable ids, string responseGroup) - { - return await ((IPricingRepository)repository).GetPricelistAssignmentsByIdAsync(ids); - } - - protected override Task BeforeSaveChanges(IEnumerable models) - { - _validator.ValidateAndThrow(models); - - return base.BeforeSaveChanges(models); - } - - protected override void ClearCache(IEnumerable models) - { - foreach (var assignment in models) - { - GenericCachingRegion.ExpireTokenForKey(assignment.Id); - GenericCachingRegion.ExpireTokenForKey(assignment.PricelistId); - } - GenericSearchCachingRegion.ExpireRegion(); - GenericCachingRegion.ExpireRegion(); } } } diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistService.cs index ead373e1..1c433eb4 100644 --- a/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistService.cs +++ b/src/VirtoCommerce.PricingModule.Data/Services/Crud/PricelistService.cs @@ -1,27 +1,19 @@ using System; -using System.Collections.Generic; -using System.Threading.Tasks; using VirtoCommerce.Platform.Core.Caching; -using VirtoCommerce.Platform.Core.Common; using VirtoCommerce.Platform.Core.Events; -using VirtoCommerce.Platform.Data.GenericCrud; using VirtoCommerce.PricingModule.Core.Events; using VirtoCommerce.PricingModule.Core.Model; using VirtoCommerce.PricingModule.Data.Model; using VirtoCommerce.PricingModule.Data.Repositories; +using VirtoCommerce.PricingModule.Data.Services.Crud.Basic; namespace VirtoCommerce.PricingModule.Data.Services { - public class PricelistService : CrudService + public class PricelistService : BasicPricelistService { public PricelistService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, IEventPublisher eventPublisher) : base(repositoryFactory, platformMemoryCache, eventPublisher) { } - - protected override async Task> LoadEntities(IRepository repository, IEnumerable ids, string responseGroup) - { - return await ((IPricingRepository)repository).GetPricelistByIdsAsync(ids, responseGroup); - } } } diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPriceSearchService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPriceSearchService.cs new file mode 100644 index 00000000..1ff90f35 --- /dev/null +++ b/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPriceSearchService.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using VirtoCommerce.CatalogModule.Core.Model; +using VirtoCommerce.CatalogModule.Core.Model.Search; +using VirtoCommerce.CatalogModule.Core.Search; +using VirtoCommerce.Platform.Caching; +using VirtoCommerce.Platform.Core.Caching; +using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.GenericCrud; +using VirtoCommerce.Platform.Data.GenericCrud; +using VirtoCommerce.Platform.Data.Infrastructure; +using VirtoCommerce.PricingModule.Core.Model; +using VirtoCommerce.PricingModule.Core.Model.Search; +using VirtoCommerce.PricingModule.Data.Model; +using VirtoCommerce.PricingModule.Data.Repositories; + +namespace VirtoCommerce.PricingModule.Data.Services.Search.Basic +{ + public class BasicPriceSearchService : SearchService where TModel : Price where TEntity : PriceEntity, Platform.Core.Domain.IDataEntity where TResult: GenericSearchResult + { + private readonly IProductIndexedSearchService _productIndexedSearchService; + private readonly Dictionary _pricesSortingAliases = new Dictionary(); + + public BasicPriceSearchService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, + ICrudService priceService, IProductIndexedSearchService productIndexedSearchService) + : base(repositoryFactory, platformMemoryCache, priceService) + { + _pricesSortingAliases["prices"] = ReflectionUtility.GetPropertyName(x => x.List); + _productIndexedSearchService = productIndexedSearchService; + } + + public override Task SearchAsync(PricesSearchCriteria criteria) + { + var cacheKey = CacheKey.With(GetType(), nameof(SearchAsync), criteria.GetCacheKey()); + return _platformMemoryCache.GetOrCreateExclusiveAsync(cacheKey, async cacheEntry => + { + cacheEntry.AddExpirationToken(GenericCachingRegion.CreateChangeToken()); + cacheEntry.AddExpirationToken(GenericSearchCachingRegion.CreateChangeToken()); + + var result = AbstractTypeFactory.TryCreateInstance(); + + using (var repository = _repositoryFactory()) + { + repository.DisableChangesTracking(); + var query = await BuildQueryAsync(repository, criteria); + var sortInfos = BuildSortExpression(criteria); + //Try to replace sorting columns names + TryTransformSortingInfoColumnNames(_pricesSortingAliases, sortInfos); + + if (criteria.GroupByProducts) + { + // unique priced product IDs + var pricedProductsQuery = query.Select(x => x.ProductId).OrderBy(x => x).Distinct(); + result.TotalCount = await pricedProductsQuery.CountAsync(); + + if (criteria.Take > 0) + { + query = query.Where(x => pricedProductsQuery + .OrderBy(x => x) + .Skip(criteria.Skip).Take(criteria.Take).Contains(x.ProductId)); + } + } + else + { + result.TotalCount = await query.CountAsync(); + + query = query.Skip(criteria.Skip).Take(criteria.Take); + } + + if (criteria.Take > 0) + { + var priceIds = await query.OrderBySortInfos(sortInfos).ThenBy(x => x.Id) + .Select(x => x.Id) + .AsNoTracking() + .ToListAsync(); + + var unorderedResults = await _crudService.GetAsync(priceIds); + result.Results = unorderedResults.OrderBy(x => priceIds.IndexOf(x.Id)).ToList(); + } + } + return result; + }); + } + + protected override IQueryable BuildQuery(IRepository repository, PricesSearchCriteria criteria) + { + return BuildQueryAsync(repository, criteria).GetAwaiter().GetResult(); + } + + protected override IList BuildSortExpression(PricesSearchCriteria criteria) + { + var sortInfos = criteria.SortInfos; + if (sortInfos.IsNullOrEmpty()) + { + sortInfos = new[] + { + new SortInfo + { + SortColumn = nameof(PriceEntity.List) + } + }; + } + return sortInfos; + } + + private async Task> BuildQueryAsync(IRepository repository, PricesSearchCriteria criteria) + { + var query = (IQueryable)((IPricingRepository)repository).Prices; + + if (!criteria.PriceListIds.IsNullOrEmpty()) + { + query = query.Where(x => criteria.PriceListIds.Contains(x.PricelistId)); + } + + if (!criteria.ProductIds.IsNullOrEmpty()) + { + query = query.Where(x => criteria.ProductIds.Contains(x.ProductId)); + } + + if (criteria.ModifiedSince.HasValue) + { + query = query.Where(x => x.ModifiedDate >= criteria.ModifiedSince); + } + + if (!string.IsNullOrEmpty(criteria.Keyword)) + { + var searchCriteria = AbstractTypeFactory.TryCreateInstance(); + searchCriteria.Keyword = criteria.Keyword; + searchCriteria.Skip = criteria.Skip; + searchCriteria.Take = criteria.Take; + searchCriteria.Sort = criteria.Sort.Replace("product.", string.Empty); + searchCriteria.ResponseGroup = ItemResponseGroup.ItemInfo.ToString(); + searchCriteria.WithHidden = true; + var searchResult = await _productIndexedSearchService.SearchAsync(searchCriteria); + + var productIds = searchResult.Items.Select(x => x.Id); + + query = query.Where(x => productIds.Contains(x.ProductId)); + } + + return query; + } + + private static void TryTransformSortingInfoColumnNames(IDictionary transformationMap, IEnumerable sortingInfos) + { + foreach (var sortInfo in sortingInfos) + { + if (transformationMap.TryGetValue(sortInfo.SortColumn.ToLowerInvariant(), out var newColumnName)) + { + sortInfo.SortColumn = newColumnName; + } + } + } + } +} diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistAssignmentSearchService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistAssignmentSearchService.cs new file mode 100644 index 00000000..ad2f9992 --- /dev/null +++ b/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistAssignmentSearchService.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using VirtoCommerce.Platform.Core.Caching; +using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.GenericCrud; +using VirtoCommerce.Platform.Data.GenericCrud; +using VirtoCommerce.PricingModule.Core.Model; +using VirtoCommerce.PricingModule.Core.Model.Search; +using VirtoCommerce.PricingModule.Data.Model; +using VirtoCommerce.PricingModule.Data.Repositories; + + +namespace VirtoCommerce.PricingModule.Data.Services.Search.Basic +{ + public class BasicPricelistAssignmentSearchService : SearchService where TModel : PricelistAssignment where TEntity : PricelistAssignmentEntity, Platform.Core.Domain.IDataEntity where TResult : GenericSearchResult + { + public BasicPricelistAssignmentSearchService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, + ICrudService pricelistAssignmentService) + : base(repositoryFactory, platformMemoryCache, pricelistAssignmentService) + { + } + + + protected override IQueryable BuildQuery(IRepository repository, PricelistAssignmentsSearchCriteria criteria) + { + var query = (IQueryable) ((IPricingRepository)repository).PricelistAssignments; + + if (!criteria.PriceListIds.IsNullOrEmpty()) + { + query = query.Where(x => criteria.PriceListIds.Contains(x.PricelistId)); + } + + if (!string.IsNullOrEmpty(criteria.Keyword)) + { + query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Description.Contains(criteria.Keyword)); + } + + if (!criteria.StoreIds.IsNullOrEmpty()) + { + query = query.Where(x => criteria.StoreIds.Contains(x.StoreId)); + } + + if (!criteria.CatalogIds.IsNullOrEmpty()) + { + query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId)); + } + + return query; + } + + protected override IList BuildSortExpression(PricelistAssignmentsSearchCriteria criteria) + { + var sortInfos = criteria.SortInfos; + if (sortInfos.IsNullOrEmpty()) + { + sortInfos = new[] + { + new SortInfo + { + SortColumn = nameof(PricelistAssignment.Priority) + } + }; + } + return sortInfos; + } + } +} diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistSearchService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistSearchService.cs new file mode 100644 index 00000000..abed1910 --- /dev/null +++ b/src/VirtoCommerce.PricingModule.Data/Services/Search/Basic/BasicPricelistSearchService.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using VirtoCommerce.Platform.Core.Caching; +using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.GenericCrud; +using VirtoCommerce.Platform.Data.GenericCrud; +using VirtoCommerce.PricingModule.Core.Model; +using VirtoCommerce.PricingModule.Core.Model.Search; +using VirtoCommerce.PricingModule.Data.Model; +using VirtoCommerce.PricingModule.Data.Repositories; + +namespace VirtoCommerce.PricingModule.Data.Services.Search.Basic +{ + public class BasicPricelistSearchService : SearchService where TModel: Pricelist where TEntity: PricelistEntity, Platform.Core.Domain.IDataEntity where TResult : GenericSearchResult + { + + public BasicPricelistSearchService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, + ICrudService pricelistService) + : base(repositoryFactory, platformMemoryCache, pricelistService) + { + } + + protected override IQueryable BuildQuery(IRepository repository, PricelistSearchCriteria criteria) + { + var query = (IQueryable) ((IPricingRepository)repository).Pricelists; + + if (!string.IsNullOrEmpty(criteria.Keyword)) + { + query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Description.Contains(criteria.Keyword)); + } + + if (!criteria.Currencies.IsNullOrEmpty()) + { + query = query.Where(x => criteria.Currencies.Contains(x.Currency)); + } + + if (!criteria.ObjectIds.IsNullOrEmpty()) + { + query = query.Where(x => criteria.ObjectIds.Contains(x.Id)); + } + + return query; + } + + protected override IList BuildSortExpression(PricelistSearchCriteria criteria) + { + var sortInfos = criteria.SortInfos; + if (sortInfos.IsNullOrEmpty()) + { + sortInfos = new[] + { + new SortInfo + { + SortColumn = nameof(PricelistEntity.Name) + } + }; + } + return sortInfos; + } + } +} diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Search/PriceSearchService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Search/PriceSearchService.cs index 57fac669..7d53c6fb 100644 --- a/src/VirtoCommerce.PricingModule.Data/Services/Search/PriceSearchService.cs +++ b/src/VirtoCommerce.PricingModule.Data/Services/Search/PriceSearchService.cs @@ -1,159 +1,21 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Caching.Memory; -using VirtoCommerce.CatalogModule.Core.Model; -using VirtoCommerce.CatalogModule.Core.Model.Search; using VirtoCommerce.CatalogModule.Core.Search; -using VirtoCommerce.Platform.Caching; using VirtoCommerce.Platform.Core.Caching; -using VirtoCommerce.Platform.Core.Common; using VirtoCommerce.Platform.Core.GenericCrud; -using VirtoCommerce.Platform.Data.GenericCrud; -using VirtoCommerce.Platform.Data.Infrastructure; using VirtoCommerce.PricingModule.Core.Model; using VirtoCommerce.PricingModule.Core.Model.Search; using VirtoCommerce.PricingModule.Data.Model; using VirtoCommerce.PricingModule.Data.Repositories; +using VirtoCommerce.PricingModule.Data.Services.Search.Basic; namespace VirtoCommerce.PricingModule.Data.Services { - public class PriceSearchService : SearchService + public class PriceSearchService : BasicPriceSearchService { - private readonly IProductIndexedSearchService _productIndexedSearchService; - private readonly Dictionary _pricesSortingAliases = new Dictionary(); - public PriceSearchService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, ICrudService priceService, IProductIndexedSearchService productIndexedSearchService) - : base(repositoryFactory, platformMemoryCache, priceService) - { - _pricesSortingAliases["prices"] = ReflectionUtility.GetPropertyName(x => x.List); - _productIndexedSearchService = productIndexedSearchService; - } - - public override Task SearchAsync(PricesSearchCriteria criteria) - { - var cacheKey = CacheKey.With(GetType(), nameof(SearchAsync), criteria.GetCacheKey()); - return _platformMemoryCache.GetOrCreateExclusiveAsync(cacheKey, async cacheEntry => - { - cacheEntry.AddExpirationToken(GenericCachingRegion.CreateChangeToken()); - cacheEntry.AddExpirationToken(GenericSearchCachingRegion.CreateChangeToken()); - - var result = AbstractTypeFactory.TryCreateInstance(); - - using (var repository = _repositoryFactory()) - { - repository.DisableChangesTracking(); - var query = await BuildQueryAsync(repository, criteria); - var sortInfos = BuildSortExpression(criteria); - //Try to replace sorting columns names - TryTransformSortingInfoColumnNames(_pricesSortingAliases, sortInfos); - - if (criteria.GroupByProducts) - { - // unique priced product IDs - var pricedProductsQuery = query.Select(x => x.ProductId).OrderBy(x => x).Distinct(); - result.TotalCount = await pricedProductsQuery.CountAsync(); - - if (criteria.Take > 0) - { - query = query.Where(x => pricedProductsQuery - .OrderBy(x => x) - .Skip(criteria.Skip).Take(criteria.Take).Contains(x.ProductId)); - } - } - else - { - result.TotalCount = await query.CountAsync(); - - query = query.Skip(criteria.Skip).Take(criteria.Take); - } - - if (criteria.Take > 0) - { - var priceIds = await query.OrderBySortInfos(sortInfos).ThenBy(x => x.Id) - .Select(x => x.Id) - .AsNoTracking() - .ToListAsync(); - - var unorderedResults = await _crudService.GetByIdsAsync(priceIds); - result.Results = unorderedResults.OrderBy(x => priceIds.IndexOf(x.Id)).ToList(); - } - } - return result; - }); - } - - protected override IQueryable BuildQuery(IRepository repository, PricesSearchCriteria criteria) - { - return BuildQueryAsync(repository, criteria).GetAwaiter().GetResult(); - } - - protected override IList BuildSortExpression(PricesSearchCriteria criteria) - { - var sortInfos = criteria.SortInfos; - if (sortInfos.IsNullOrEmpty()) - { - sortInfos = new[] - { - new SortInfo - { - SortColumn = nameof(PriceEntity.List) - } - }; - } - return sortInfos; - } - - private async Task> BuildQueryAsync(IRepository repository, PricesSearchCriteria criteria) - { - var query = ((IPricingRepository)repository).Prices; - - if (!criteria.PriceListIds.IsNullOrEmpty()) - { - query = query.Where(x => criteria.PriceListIds.Contains(x.PricelistId)); - } - - if (!criteria.ProductIds.IsNullOrEmpty()) - { - query = query.Where(x => criteria.ProductIds.Contains(x.ProductId)); - } - - if (criteria.ModifiedSince.HasValue) - { - query = query.Where(x => x.ModifiedDate >= criteria.ModifiedSince); - } - - if (!string.IsNullOrEmpty(criteria.Keyword)) - { - var searchCriteria = AbstractTypeFactory.TryCreateInstance(); - searchCriteria.Keyword = criteria.Keyword; - searchCriteria.Skip = criteria.Skip; - searchCriteria.Take = criteria.Take; - searchCriteria.Sort = criteria.Sort.Replace("product.", string.Empty); - searchCriteria.ResponseGroup = ItemResponseGroup.ItemInfo.ToString(); - searchCriteria.WithHidden = true; - var searchResult = await _productIndexedSearchService.SearchAsync(searchCriteria); - - var productIds = searchResult.Items.Select(x => x.Id); - - query = query.Where(x => productIds.Contains(x.ProductId)); - } - - return query; - } - - private static void TryTransformSortingInfoColumnNames(IDictionary transformationMap, IEnumerable sortingInfos) + : base(repositoryFactory, platformMemoryCache, priceService, productIndexedSearchService) { - foreach (var sortInfo in sortingInfos) - { - if (transformationMap.TryGetValue(sortInfo.SortColumn.ToLowerInvariant(), out var newColumnName)) - { - sortInfo.SortColumn = newColumnName; - } - } } } } diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistAssignmentSearchService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistAssignmentSearchService.cs index f220f6ac..9a390a19 100644 --- a/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistAssignmentSearchService.cs +++ b/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistAssignmentSearchService.cs @@ -9,59 +9,16 @@ using VirtoCommerce.PricingModule.Core.Model.Search; using VirtoCommerce.PricingModule.Data.Model; using VirtoCommerce.PricingModule.Data.Repositories; +using VirtoCommerce.PricingModule.Data.Services.Search.Basic; namespace VirtoCommerce.PricingModule.Data.Services { - public class PricelistAssignmentSearchService : SearchService + public class PricelistAssignmentSearchService : BasicPricelistAssignmentSearchService { - public PricelistAssignmentSearchService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, ICrudService pricelistAssignmentService) : base(repositoryFactory, platformMemoryCache, pricelistAssignmentService) { } - - protected override IQueryable BuildQuery(IRepository repository, PricelistAssignmentsSearchCriteria criteria) - { - var query = ((IPricingRepository)repository).PricelistAssignments; - - if (!criteria.PriceListIds.IsNullOrEmpty()) - { - query = query.Where(x => criteria.PriceListIds.Contains(x.PricelistId)); - } - - if (!string.IsNullOrEmpty(criteria.Keyword)) - { - query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Description.Contains(criteria.Keyword)); - } - - if (!criteria.StoreIds.IsNullOrEmpty()) - { - query = query.Where(x => criteria.StoreIds.Contains(x.StoreId)); - } - - if (!criteria.CatalogIds.IsNullOrEmpty()) - { - query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId)); - } - - return query; - } - - protected override IList BuildSortExpression(PricelistAssignmentsSearchCriteria criteria) - { - var sortInfos = criteria.SortInfos; - if (sortInfos.IsNullOrEmpty()) - { - sortInfos = new[] - { - new SortInfo - { - SortColumn = nameof(PricelistAssignment.Priority) - } - }; - } - return sortInfos; - } } } diff --git a/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistSearchService.cs b/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistSearchService.cs index bef56a73..26cf9056 100644 --- a/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistSearchService.cs +++ b/src/VirtoCommerce.PricingModule.Data/Services/Search/PricelistSearchService.cs @@ -1,62 +1,20 @@ using System; -using System.Collections.Generic; -using System.Linq; using VirtoCommerce.Platform.Core.Caching; -using VirtoCommerce.Platform.Core.Common; using VirtoCommerce.Platform.Core.GenericCrud; -using VirtoCommerce.Platform.Data.GenericCrud; using VirtoCommerce.PricingModule.Core.Model; using VirtoCommerce.PricingModule.Core.Model.Search; using VirtoCommerce.PricingModule.Data.Model; using VirtoCommerce.PricingModule.Data.Repositories; +using VirtoCommerce.PricingModule.Data.Services.Search.Basic; namespace VirtoCommerce.PricingModule.Data.Services { - public class PricelistSearchService : SearchService + public class PricelistSearchService : BasicPricelistSearchService { - public PricelistSearchService(Func repositoryFactory, IPlatformMemoryCache platformMemoryCache, ICrudService pricelistService) : base(repositoryFactory, platformMemoryCache, pricelistService) { } - - protected override IQueryable BuildQuery(IRepository repository, PricelistSearchCriteria criteria) - { - var query = ((IPricingRepository)repository).Pricelists; - - if (!string.IsNullOrEmpty(criteria.Keyword)) - { - query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Description.Contains(criteria.Keyword)); - } - - if (!criteria.Currencies.IsNullOrEmpty()) - { - query = query.Where(x => criteria.Currencies.Contains(x.Currency)); - } - - if (!criteria.ObjectIds.IsNullOrEmpty()) - { - query = query.Where(x => criteria.ObjectIds.Contains(x.Id)); - } - - return query; - } - - protected override IList BuildSortExpression(PricelistSearchCriteria criteria) - { - var sortInfos = criteria.SortInfos; - if (sortInfos.IsNullOrEmpty()) - { - sortInfos = new[] - { - new SortInfo - { - SortColumn = nameof(PricelistEntity.Name) - } - }; - } - return sortInfos; - } } }