test bild upploas
All checks were successful
Branch - test - Build and Push Backend API Docker Image / build-and-push (push) Successful in 25s

This commit is contained in:
Tizian.Breuch
2025-11-07 10:42:58 +01:00
parent 3f1874f7c2
commit 56d3d6a169
2 changed files with 42 additions and 18 deletions

View File

@@ -74,7 +74,7 @@ namespace Webshop.Application.Services.Admin
var slugExists = await _context.Products.AnyAsync(p => p.Slug == productDto.Slug && p.Id != productDto.Id); 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."); } 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.Name = productDto.Name;
existingProduct.Description = productDto.Description; existingProduct.Description = productDto.Description;
existingProduct.SKU = productDto.SKU; existingProduct.SKU = productDto.SKU;
@@ -91,7 +91,7 @@ namespace Webshop.Application.Services.Admin
existingProduct.FeaturedDisplayOrder = productDto.FeaturedDisplayOrder; existingProduct.FeaturedDisplayOrder = productDto.FeaturedDisplayOrder;
existingProduct.LastModifiedDate = DateTimeOffset.UtcNow; existingProduct.LastModifiedDate = DateTimeOffset.UtcNow;
// Kategorien direkt bearbeiten // --- Kategorien neu aufbauen ---
existingProduct.Productcategories.Clear(); existingProduct.Productcategories.Clear();
if (productDto.CategorieIds != null) if (productDto.CategorieIds != null)
{ {
@@ -100,38 +100,66 @@ namespace Webshop.Application.Services.Admin
existingProduct.Productcategories.Add(new Productcategorie { categorieId = catId }); existingProduct.Productcategories.Add(new Productcategorie { categorieId = catId });
} }
} }
// --- ENDE DIREKTE ZUWEISUNG ---
// Logik f<>r Bilder (unver<65>ndert) // =========================================================================
// --- BILD-LOGIK (SAUBER REFAKTORISIERT MIT "COLLECTION-NEUBAU") ---
// =========================================================================
var newImageList = new List<ProductImage>();
// 1. Behalte alle existierenden Bilder, die NICHT gel<65>scht werden sollen
if (productDto.ImagesToDelete != null && productDto.ImagesToDelete.Any()) if (productDto.ImagesToDelete != null && productDto.ImagesToDelete.Any())
{ {
var imagesToRemove = existingProduct.Images.Where(img => productDto.ImagesToDelete.Contains(img.Id)).ToList(); newImageList.AddRange(existingProduct.Images.Where(img => !productDto.ImagesToDelete.Contains(img.Id)));
foreach (var image in imagesToRemove) { existingProduct.Images.Remove(image); }
} }
else
{
newImageList.AddRange(existingProduct.Images);
}
// 2. Verarbeite das neue Hauptbild (falls vorhanden)
if (productDto.MainImageFile != null) if (productDto.MainImageFile != null)
{ {
var oldMainImage = existingProduct.Images.FirstOrDefault(i => i.IsMainImage); // Altes Hauptbild aus der neuen Liste entfernen (falls vorhanden)
if (oldMainImage != null) { existingProduct.Images.Remove(oldMainImage); } var oldMainImage = newImageList.FirstOrDefault(i => i.IsMainImage);
foreach (var img in existingProduct.Images) { img.IsMainImage = false; } 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<75>gen
await using var stream = productDto.MainImageFile.OpenReadStream(); await using var stream = productDto.MainImageFile.OpenReadStream();
var url = await _fileStorageService.SaveFileAsync(stream, productDto.MainImageFile.FileName, productDto.MainImageFile.ContentType); 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<75>tzliche neue Bilder (falls vorhanden)
if (productDto.AdditionalImageFiles != null && productDto.AdditionalImageFiles.Any()) if (productDto.AdditionalImageFiles != null && productDto.AdditionalImageFiles.Any())
{ {
foreach (var file in productDto.AdditionalImageFiles) foreach (var file in productDto.AdditionalImageFiles)
{ {
await using var stream = file.OpenReadStream(); await using var stream = file.OpenReadStream();
var url = await _fileStorageService.SaveFileAsync(stream, file.FileName, file.ContentType); 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; 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++; 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. <20>nderungen <20>ber das Repository speichern
await _productRepository.UpdateProductAsync(existingProduct); await _productRepository.UpdateProductAsync(existingProduct);
return ServiceResult.Ok(); return ServiceResult.Ok();

View File

@@ -51,12 +51,8 @@ namespace Webshop.Infrastructure.Repositories
// --- KORRIGIERTE UPDATE-METHODE (OHNE PARAMETER) --- // --- KORRIGIERTE UPDATE-METHODE (OHNE PARAMETER) ---
public async Task UpdateProductAsync(Product product) public async Task UpdateProductAsync(Product product)
{ {
// Wir sagen dem DbContext explizit, dass der Zustand dieser Entität "Modifiziert" ist. // Sagen Sie EF explizit, was es tun soll. Das ist der robusteste Weg.
// Das zwingt EF Core dazu, ALLE Eigenschaften der Entität in der UPDATE-Anweisung zu berücksichtigen. _context.Products.Update(product);
// 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;
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }