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}" ))); } }