public async Task SaveChangesAsync(ShippingMethod[] shippingMethods)
        {
            var pkMap = new PrimaryKeyResolvingMap();

            using (var repository = _repositoryFactory())
            {
                var dataExistEntities = await repository.GetStoreShippingMethodsByIdsAsync(shippingMethods.Where(x => !x.IsTransient())
                                                                                           .Select(x => x.Id)
                                                                                           .ToArray());

                foreach (var shippingMethod in shippingMethods)
                {
                    var originalEntity = dataExistEntities.FirstOrDefault(x => x.Id == shippingMethod.Id);
                    var modifiedEntity = AbstractTypeFactory <StoreShippingMethodEntity> .TryCreateInstance().FromModel(shippingMethod, pkMap);

                    if (originalEntity != null)
                    {
                        modifiedEntity.Patch(originalEntity);
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                    }
                }

                //Raise domain events
                await repository.UnitOfWork.CommitAsync();

                pkMap.ResolvePrimaryKeys();
                //Save settings
                await _settingManager.DeepSaveSettingsAsync(shippingMethods);
            }

            ShippingCacheRegion.ExpireRegion();
        }
        public async Task <ShippingMethod[]> GetByIdsAsync(string[] ids, string responseGroup)
        {
            var cacheKey = CacheKey.With(GetType(), "GetByIdsAsync", string.Join("-", ids));

            return(await _memCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                var result = new List <ShippingMethod>();

                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();
                    var existEntities = await repository.GetStoreShippingMethodsByIdsAsync(ids, responseGroup);
                    foreach (var existEntity in existEntities)
                    {
                        var shippingMethod = AbstractTypeFactory <ShippingMethod> .TryCreateInstance(string.IsNullOrEmpty(existEntity.TypeName) ? $"{existEntity.Code}ShippingMethod" : existEntity.TypeName);
                        if (shippingMethod != null)
                        {
                            existEntity.ToModel(shippingMethod);

                            await _settingManager.DeepLoadSettingsAsync(shippingMethod);
                            result.Add(shippingMethod);
                        }
                    }
                    cacheEntry.AddExpirationToken(ShippingCacheRegion.CreateChangeToken());
                    return result.ToArray();
                }
            }));
        }
        public async Task <ShippingMethodsSearchResult> SearchShippingMethodsAsync(ShippingMethodsSearchCriteria criteria)
        {
            var cacheKey = CacheKey.With(GetType(), "SearchShippingMethodsAsync", criteria.GetCacheKey());

            return(await _memCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(ShippingCacheRegion.CreateChangeToken());
                var result = AbstractTypeFactory <ShippingMethodsSearchResult> .TryCreateInstance();

                var tmpSkip = 0;
                var tmpTake = 0;

                var sortInfos = GetSortInfos(criteria);

                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();
                    var query = GetQuery(repository, criteria, sortInfos);

                    result.TotalCount = await query.CountAsync();
                    if (criteria.Take > 0)
                    {
                        var shippingMethodsIds = await query.Select(x => x.Id)
                                                 .Skip(criteria.Skip)
                                                 .Take(criteria.Take)
                                                 .ToArrayAsync();

                        result.Results = (await _shippingMethodsService.GetByIdsAsync(shippingMethodsIds, criteria.ResponseGroup))
                                         .AsQueryable()
                                         .OrderBySortInfos(sortInfos)
                                         .ToArray();
                    }
                }

                //Need to concatenate persistent methods with registered types and still not persisted
                tmpSkip = Math.Min(result.TotalCount, criteria.Skip);
                tmpTake = Math.Min(criteria.Take, Math.Max(0, result.TotalCount - criteria.Skip));
                criteria.Skip = criteria.Skip - tmpSkip;
                criteria.Take = criteria.Take - tmpTake;
                if (criteria.Take > 0 && !criteria.WithoutTransient)
                {
                    var transientMethodsQuery = AbstractTypeFactory <ShippingMethod> .AllTypeInfos.Select(x => AbstractTypeFactory <ShippingMethod> .TryCreateInstance(x.Type.Name))
                                                .OfType <ShippingMethod>().AsQueryable();
                    if (!string.IsNullOrEmpty(criteria.Keyword))
                    {
                        transientMethodsQuery = transientMethodsQuery.Where(x => x.Code.Contains(criteria.Keyword));
                    }
                    var allPersistentTypes = result.Results.Select(x => x.GetType()).Distinct();
                    transientMethodsQuery = transientMethodsQuery.Where(x => !allPersistentTypes.Contains(x.GetType()));

                    result.TotalCount += transientMethodsQuery.Count();
                    var transientProviders = transientMethodsQuery.Skip(criteria.Skip).Take(criteria.Take).ToList();

                    foreach (var transientProvider in transientProviders)
                    {
                        await _settingsManager.DeepLoadSettingsAsync(transientProvider);
                    }

                    result.Results = result.Results.Concat(transientProviders).AsQueryable().OrderBySortInfos(sortInfos).ToList();
                }

                return result;
            }));
        }