From 56d3d6a169c23198ae4df7ee40c3effa25101a01 Mon Sep 17 00:00:00 2001 From: "Tizian.Breuch" Date: Fri, 7 Nov 2025 10:42:58 +0100 Subject: [PATCH] test bild upploas --- .../Services/Admin/AdminProductService.cs | 52 ++++++++++++++----- .../Repositories/ProductRepository.cs | 8 +-- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/Webshop.Application/Services/Admin/AdminProductService.cs b/Webshop.Application/Services/Admin/AdminProductService.cs index 744bb84..ae263c5 100644 --- a/Webshop.Application/Services/Admin/AdminProductService.cs +++ b/Webshop.Application/Services/Admin/AdminProductService.cs @@ -74,7 +74,7 @@ namespace Webshop.Application.Services.Admin var slugExists = await _context.Products.AnyAsync(p => p.Slug == productDto.Slug && p.Id != productDto.Id); if (slugExists) { return ServiceResult.Fail(ServiceResultType.Conflict, $"Ein anderes Produkt mit dem Slug '{productDto.Slug}' existiert bereits."); } - // --- DIREKTE ZUWEISUNG STATT UpdateFromDto --- + // --- Produkteigenschaften direkt zuweisen --- existingProduct.Name = productDto.Name; existingProduct.Description = productDto.Description; existingProduct.SKU = productDto.SKU; @@ -91,7 +91,7 @@ namespace Webshop.Application.Services.Admin existingProduct.FeaturedDisplayOrder = productDto.FeaturedDisplayOrder; existingProduct.LastModifiedDate = DateTimeOffset.UtcNow; - // Kategorien direkt bearbeiten + // --- Kategorien neu aufbauen --- existingProduct.Productcategories.Clear(); if (productDto.CategorieIds != null) { @@ -100,38 +100,66 @@ namespace Webshop.Application.Services.Admin existingProduct.Productcategories.Add(new Productcategorie { categorieId = catId }); } } - // --- ENDE DIREKTE ZUWEISUNG --- - // Logik für Bilder (unverändert) + // ========================================================================= + // --- BILD-LOGIK (SAUBER REFAKTORISIERT MIT "COLLECTION-NEUBAU") --- + // ========================================================================= + var newImageList = new List(); + + // 1. Behalte alle existierenden Bilder, die NICHT gelöscht werden sollen if (productDto.ImagesToDelete != null && productDto.ImagesToDelete.Any()) { - var imagesToRemove = existingProduct.Images.Where(img => productDto.ImagesToDelete.Contains(img.Id)).ToList(); - foreach (var image in imagesToRemove) { existingProduct.Images.Remove(image); } + newImageList.AddRange(existingProduct.Images.Where(img => !productDto.ImagesToDelete.Contains(img.Id))); } + else + { + newImageList.AddRange(existingProduct.Images); + } + + // 2. Verarbeite das neue Hauptbild (falls vorhanden) if (productDto.MainImageFile != null) { - var oldMainImage = existingProduct.Images.FirstOrDefault(i => i.IsMainImage); - if (oldMainImage != null) { existingProduct.Images.Remove(oldMainImage); } - foreach (var img in existingProduct.Images) { img.IsMainImage = false; } + // Altes Hauptbild aus der neuen Liste entfernen (falls vorhanden) + var oldMainImage = newImageList.FirstOrDefault(i => i.IsMainImage); + if (oldMainImage != null) + { + newImageList.Remove(oldMainImage); + } + + // Alle verbleibenden Bilder als "nicht Hauptbild" markieren + foreach (var img in newImageList) { img.IsMainImage = false; } + + // Neues Hauptbild hochladen und zur neuen Liste hinzufügen await using var stream = productDto.MainImageFile.OpenReadStream(); var url = await _fileStorageService.SaveFileAsync(stream, productDto.MainImageFile.FileName, productDto.MainImageFile.ContentType); - existingProduct.Images.Add(new ProductImage { Url = url, IsMainImage = true }); + newImageList.Add(new ProductImage { Url = url, IsMainImage = true }); } + + // 3. Verarbeite zusätzliche neue Bilder (falls vorhanden) if (productDto.AdditionalImageFiles != null && productDto.AdditionalImageFiles.Any()) { foreach (var file in productDto.AdditionalImageFiles) { await using var stream = file.OpenReadStream(); var url = await _fileStorageService.SaveFileAsync(stream, file.FileName, file.ContentType); - existingProduct.Images.Add(new ProductImage { Url = url, IsMainImage = false }); + newImageList.Add(new ProductImage { Url = url, IsMainImage = false }); } } + + // 4. Berechne die DisplayOrder für die finale neue Liste int currentOrder = 1; - foreach (var image in existingProduct.Images.OrderBy(img => !img.IsMainImage).ThenBy(img => img.Id)) + foreach (var image in newImageList.OrderBy(img => !img.IsMainImage).ThenBy(img => img.Id)) { image.DisplayOrder = currentOrder++; } + // 5. Ersetze die alte Bild-Collection komplett durch die neue. + // EF Core vergleicht die alte und die neue Liste und generiert die nötigen SQL-Befehle. + existingProduct.Images = newImageList; + + // --- ENDE BILD-LOGIK --- + + // 6. Änderungen über das Repository speichern await _productRepository.UpdateProductAsync(existingProduct); return ServiceResult.Ok(); diff --git a/Webshop.Infrastructure/Repositories/ProductRepository.cs b/Webshop.Infrastructure/Repositories/ProductRepository.cs index e5f32cb..394d5af 100644 --- a/Webshop.Infrastructure/Repositories/ProductRepository.cs +++ b/Webshop.Infrastructure/Repositories/ProductRepository.cs @@ -51,12 +51,8 @@ namespace Webshop.Infrastructure.Repositories // --- KORRIGIERTE UPDATE-METHODE (OHNE PARAMETER) --- public async Task UpdateProductAsync(Product product) { - // Wir sagen dem DbContext explizit, dass der Zustand dieser Entität "Modifiziert" ist. - // Das zwingt EF Core dazu, ALLE Eigenschaften der Entität in der UPDATE-Anweisung zu berücksichtigen. - // Es umgeht alle möglichen Probleme mit dem Change Tracking, die durch verschiedene Kontexte - // oder komplexe Beziehungs-Updates entstehen können. - _context.Entry(product).State = EntityState.Modified; - + // Sagen Sie EF explizit, was es tun soll. Das ist der robusteste Weg. + _context.Products.Update(product); await _context.SaveChangesAsync(); }