From eebfcdf3c73d513cb3738d92454345cd2f99fd07 Mon Sep 17 00:00:00 2001 From: "Tizian.Breuch" Date: Fri, 7 Nov 2025 15:48:05 +0100 Subject: [PATCH] test --- .../DTOs/Products/UpdateAdminProductDto.cs | 2 +- .../Services/Admin/AdminProductService.cs | 38 +++++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Webshop.Application/DTOs/Products/UpdateAdminProductDto.cs b/Webshop.Application/DTOs/Products/UpdateAdminProductDto.cs index 61a02af..70871d8 100644 --- a/Webshop.Application/DTOs/Products/UpdateAdminProductDto.cs +++ b/Webshop.Application/DTOs/Products/UpdateAdminProductDto.cs @@ -36,6 +36,6 @@ namespace Webshop.Application.DTOs.Products public bool IsFeatured { get; set; } public int FeaturedDisplayOrder { get; set; } [Required] - public byte[] RowVersion { get; set; } + public byte[]? RowVersion { get; set; } } } \ No newline at end of file diff --git a/Webshop.Application/Services/Admin/AdminProductService.cs b/Webshop.Application/Services/Admin/AdminProductService.cs index cf69c9d..e08d4b4 100644 --- a/Webshop.Application/Services/Admin/AdminProductService.cs +++ b/Webshop.Application/Services/Admin/AdminProductService.cs @@ -112,11 +112,24 @@ namespace Webshop.Application.Services.Admin public async Task UpdateAdminProductAsync(UpdateAdminProductDto productDto) { Console.WriteLine($"---- UPDATE START: Produkt-ID {productDto.Id} ----"); - var existingProduct = await _context.Products.Include(p => p.Images).Include(p => p.Productcategories).FirstOrDefaultAsync(p => p.Id == productDto.Id); - if (existingProduct == null) { return ServiceResult.Fail(ServiceResultType.NotFound, $"Produkt mit ID '{productDto.Id}' nicht gefunden."); } + // SCHRITT 1: Lade NUR das Hauptprodukt, ohne Relationen. + var existingProduct = await _context.Products.FirstOrDefaultAsync(p => p.Id == productDto.Id); + if (existingProduct == null) + { + return ServiceResult.Fail(ServiceResultType.NotFound, $"Produkt mit ID '{productDto.Id}' nicht gefunden."); + } + + // SCHRITT 2: Setze SOFORT den Concurrency Token am "sauberen" Objekt. + if (productDto.RowVersion != null && productDto.RowVersion.Length > 0) + { + _context.Entry(existingProduct).Property(p => p.RowVersion).OriginalValue = productDto.RowVersion; + } + + // SCHRITT 3: Lade jetzt die Relationen explizit nach. + await _context.Entry(existingProduct).Collection(p => p.Images).LoadAsync(); + await _context.Entry(existingProduct).Collection(p => p.Productcategories).LoadAsync(); + - _context.Entry(existingProduct).Property(p => p.RowVersion).OriginalValue = productDto.RowVersion; - // SKU/Slug Checks bleiben gleich... var skuExists = await _context.Products.AnyAsync(p => p.SKU == productDto.SKU && p.Id != productDto.Id); if (skuExists) { return ServiceResult.Fail(ServiceResultType.Conflict, $"Ein anderes Produkt mit der SKU '{productDto.SKU}' existiert bereits."); } var slugExists = await _context.Products.AnyAsync(p => p.Slug == productDto.Slug && p.Id != productDto.Id); @@ -182,10 +195,19 @@ namespace Webshop.Application.Services.Admin } } - // --- SPEICHERN --- - Console.WriteLine("---- RUFE SaveChangesAsync AUF ----"); - await _context.SaveChangesAsync(); - Console.WriteLine("---- UPDATE BEENDET ----"); + // SCHRITT 5: Speichern (jetzt mit einem sauberen Change Tracker Zustand) + try + { + Console.WriteLine("---- RUFE SaveChangesAsync AUF ----"); + await _context.SaveChangesAsync(); + Console.WriteLine("---- UPDATE BEENDET ----"); + } + catch (DbUpdateConcurrencyException) + { + // Dieser Fehler tritt jetzt nur noch auf, wenn jemand anderes WIRKLICH + // die Daten in der Zwischenzeit geändert hat. + return ServiceResult.Fail(ServiceResultType.Conflict, "Das Produkt wurde in der Zwischenzeit von jemand anderem bearbeitet. Bitte laden Sie die Seite neu."); + } return ServiceResult.Ok(); }