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}" ))); } }
/// <inheritdoc/> public async Task <ServiceExecuteResult <int> > AddOrder(OrderCreateDTO orderDTO) { using var transaction = await _context.Database.BeginTransactionAsync(); var orderId = -1; try { /// Создаём рыбу модели заказа var order = new Order() { OrderId = 0, FIO = orderDTO.FIO, Phone = orderDTO.Phone, Email = orderDTO.Email, Date = DateTime.Now, StatusId = (int)OrderStatusEnum.New, TotalPrice = 0 }; var client = new Client() { Email = orderDTO.Email, FIO = orderDTO.FIO, Phone = orderDTO.Phone, IsIncludeInMailing = true }; await _repository.AddOrder(order); await _repository.AddClient(client); /// Прокидываем связь в позиции заказа /// с настоящим товаром order.OrderPositions = orderDTO.OrderPositions.Select(x => new OrderPosition() { OrderPositionId = 0, Number = x.Number, Price = 0, Name = "", OrderId = order.OrderId, CategoryId = x.Product.CategoryId, SubcategoryId = x.Product.SubcategoryId, ProductId = x.Product.ProductId }) .ToList(); await _repository.UpdateOrder(order); /// Подгружаем товары, которые мы связали на прошлом шагу await _context.Entry(order) .Collection(x => x.OrderPositions) .Query() .Include(x => x.Product) .LoadAsync(); foreach (var orderPos in order.OrderPositions) { orderPos.Price = orderPos.Product.Price; orderPos.Name = orderPos.Product.Alias; } order.TotalPrice = order.OrderPositions.Select(x => x.Number * x.Price).Sum(); await _repository.UpdateOrder(order); orderId = order.OrderId; transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); var msg = $"Не удалось создать заказ по след. причине: {ex.Message}"; _logger.LogError(ex, $"{msg}. Модель запроса:\n{JsonHelper.Serialize(orderDTO)}"); return(new ServiceExecuteResult <int> { IsSuccess = false, Error = msg, Result = 0 }); } try { if (orderId <= 0) { throw new Exception($"Отсутствует номер заказа."); } await _emailService.SendOrderInformation(orderId); } catch (Exception ex) { var msg = $"Не удалось отправить письмо на почту по след. причине: {ex.Message}"; _logger.LogError(ex, msg); return(new ServiceExecuteResult <int> { IsSuccess = false, Error = msg, Result = orderId != -1 ? orderId : 0 }); } return(new ServiceExecuteResult <int> { IsSuccess = true, Result = orderId, }); }
/// <inheritdoc/> public async Task LoadPhotoCollection <T>(T model) where T : IPhoto { await Context.Entry(model) .Collection("Photos") .LoadAsync(); }
public async ValueTask <(bool isSuccess, string error)> FullUpdateSubcategory(SubcategoryDTO subcategoryDTO, Subcategory oldSubcategory) { // В случае когда нам не удаётся обновить данную модель // Мы должны удалить те фото, которые были добавлены 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(newSubcategory, error) = await CreateSubcategory(subcategoryDTO, defaultPhotoList : oldSubcategory.Photos, scheduleAddedPhotoList : scheduleAddedPhotoList, scheduleDeletePhotoList : scheduleDeletePhotoList); if (newSubcategory is null) { return(cancelUpdate((false, error))); } #endregion // Загружаем список продуктов await _context .Entry(oldSubcategory) .Collection(x => x.Products) .LoadAsync(); foreach (var product in oldSubcategory.Products) { await _context .Entry(product) .Collection(x => x.Photos) .LoadAsync(); 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); } // Теперь мы можем изменить заказы, т.к. новая подкатегория и продукты добавлены 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 _context.SaveChangesAsync(); 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}" ))); } }