Пример #1
0
        private async ValueTask <(bool isSuccess, string error)> FullUpdate(CategoryDTO categoryDTO, Category oldCategory)
        {
            // В случае когда нам не удаётся обновить данную модель
            // Мы должны удалить те фото, которые были добавлены
            var scheduleAddedPhotoList = new List <Photo>();

            // Если обновление прошло успешно
            // То нужно окончательно удалить ненужные фото
            var scheduleDeletePhotoList = new List <Photo>();

            using var transaction = await _context.Database.BeginTransactionAsync();

            (bool isSuccess, string error) cancelUpdate((bool isSuccess, string error) result)
            {
                transaction.Rollback();
                return(result);
            }

            try
            {
                #region Create new entity and migrate/update photo list

                var(newCategory, error) = await this.CreateEntity(categoryDTO,
                                                                  addEntityDbFunc : _repository.AddCategory,
                                                                  defaultPhotoList : oldCategory.Photos,
                                                                  scheduleAddedPhotoList : scheduleAddedPhotoList,
                                                                  scheduleDeletePhotoList : scheduleDeletePhotoList);

                if (newCategory is null)
                {
                    return(cancelUpdate((false, error)));
                }

                var newCategoryId = newCategory.CategoryId;
                newCategory = null;

                #endregion

                // Для старой Entry (категории) загружаем из базы коллекцию (лист) подкатегорий
                await _context
                .Entry(oldCategory)
                .Collection(x => x.Subcategories)
                .LoadAsync();

                // Поскольку по окончанию цикла мы сохраняем изменения в БД
                // Список подкатегорий уменьшается, поэтому используется цикл while
                while (oldCategory.Subcategories.Count != 0)
                {
                    var oldSubcategory = oldCategory.Subcategories.ElementAt(0);
                    var newSubcategory = default(Subcategory);

                    // Загружаем для подкатегории фотографии
                    await _repository.LoadPhotoCollection(oldSubcategory);

                    // Создаём новую подкатегорию
                    newSubcategory = new Subcategory()
                    {
                        CategoryId    = newCategoryId,
                        SubcategoryId = oldSubcategory.SubcategoryId,

                        SeoTitle       = oldSubcategory.SeoTitle,
                        SeoDescription = oldSubcategory.SeoDescription,
                        SeoKeywords    = oldSubcategory.SeoKeywords,

                        Description = oldCategory.Description,

                        Alias    = oldSubcategory.Alias,
                        Products = new List <Product>(),
                        Photos   = new List <Photo>(),
                    };

                    // Удаляем фотографию для старой
                    _photoEntityUpdater.MovePhotosToEntity(newSubcategory, oldSubcategory.Photos);

                    // Загружаем список продуктов
                    await _context
                    .Entry(oldSubcategory)
                    .Collection(x => x.Products)
                    .LoadAsync();

                    foreach (var product in oldSubcategory.Products)
                    {
                        await _repository.LoadPhotoCollection(product);

                        var newProduct = new Product()
                        {
                            CategoryId    = newSubcategory.CategoryId,
                            SubcategoryId = newSubcategory.SubcategoryId,
                            ProductId     = product.ProductId,

                            Alias       = product.Alias,
                            Price       = product.Price,
                            Description = product.Description,

                            SeoTitle       = product.SeoTitle,
                            SeoDescription = product.SeoDescription,
                            SeoKeywords    = product.SeoKeywords,

                            Photos = new List <Photo>()
                        };

                        _photoEntityUpdater.MovePhotosToEntity(newProduct, product.Photos);

                        newSubcategory.Products.Add(newProduct);
                    }

                    // Добавляем новую подкатегорию
                    _context.Add(newSubcategory);

                    // Теперь мы можем изменить заказы, т.к. новая категория с подкатегорией и продуктами добавлены
                    var categoryKeys = oldSubcategory
                                       .Products
                                       .Select(x => x.CategoryId);

                    var subcategoryKeys = oldSubcategory
                                          .Products
                                          .Select(x => x.SubcategoryId);

                    var productKeys = oldSubcategory
                                      .Products
                                      .Select(x => x.ProductId);

                    var orderList = _context.OrderPosition
                                    .Where(
                        order => categoryKeys.Contains(order.Product.CategoryId) &&
                        subcategoryKeys.Contains(order.Product.SubcategoryId) &&
                        productKeys.Contains(order.Product.ProductId)
                        )
                                    .ToList();

                    // Обновляем ссылку на продукт
                    orderList.ForEach(order =>
                    {
                        var newProduct = newSubcategory.Products.First(product => oldSubcategory.CategoryId == order.Product.CategoryId &&
                                                                       product.SubcategoryId == order.Product.SubcategoryId &&
                                                                       product.ProductId == order.Product.ProductId);

                        order.Product = newProduct;

                        _context.Update(order);
                    });

                    // Теперь старая подкатегория не нужно
                    _context.Remove(oldSubcategory);

                    // Сохраняем изменения
                    await _repository.SaveChangesAsync();
                }

                // Если всё прошло удачно, удаляем старую категорию
                await _repository.DeleteCategory(oldCategory.CategoryId);

                transaction.Commit();

                foreach (var photo in scheduleDeletePhotoList)
                {
                    await _photoSaver.RemoveFileFromRepository(photo, updateDB : false);
                }

                return(true, null);
            }
            catch (Exception ex)
            {
                foreach (var photo in scheduleAddedPhotoList)
                {
                    await _photoSaver.RemoveFileFromRepository(photo, updateDB : false);
                }

                var errMsg = "Ошибка при обновлении категории. Возможно подкатегория и товар с такой категорией уже существует.";

                _logger.LogError(ex, errMsg);

                return(cancelUpdate((
                                        false,
                                        $"{errMsg} Текст ошибки: {ex.Message}"
                                        )));
            }
        }