From d8ba28a8100a335641f95afaedd18c920b1e9f87 Mon Sep 17 00:00:00 2001 From: Kleidukos Date: Sun, 16 Aug 2026 14:16:02 +0200 Subject: [PATCH] fix(news): normalize URL and clear change tracker on insert conflict to prevent concurrency exception --- FinlyticNews/Services/NewsDbService.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/FinlyticNews/Services/NewsDbService.cs b/FinlyticNews/Services/NewsDbService.cs index f1fd628..73a3912 100644 --- a/FinlyticNews/Services/NewsDbService.cs +++ b/FinlyticNews/Services/NewsDbService.cs @@ -104,9 +104,10 @@ public class NewsDbService : INewsDbService string? language = null) { var trimmedUrl = url.Trim(); + var cleanUrl = trimmedUrl.TrimEnd('.', '/'); var existingArticle = await _context.NewsArticles - .FirstOrDefaultAsync(a => a.SourceUrl == trimmedUrl); + .FirstOrDefaultAsync(a => a.SourceUrl == trimmedUrl || a.SourceUrl == cleanUrl || a.SourceUrl.StartsWith(cleanUrl)); if (existingArticle != null) { @@ -160,21 +161,14 @@ public class NewsDbService : INewsDbService } catch (DbUpdateException ex) { - _context.Entry(article).State = EntityState.Detached; - if (article.MatchedAssets != null) - { - foreach (var match in article.MatchedAssets) - { - _context.Entry(match).State = EntityState.Detached; - } - } + _context.ChangeTracker.Clear(); await _finlyticLogger.LogWarningAsync(SettingKeys.NewsChannel, "[NewsChannel] Unique constraint or concurrency hit during insert for URL: {Url}. Fetching existing fallback. ({Message})", trimmedUrl, ex.InnerException?.Message ?? ex.Message); - var existing = await _context.NewsArticles.AsNoTracking().FirstOrDefaultAsync(a => a.SourceUrl == trimmedUrl); + var existing = await _context.NewsArticles.AsNoTracking().FirstOrDefaultAsync(a => a.SourceUrl == trimmedUrl || a.SourceUrl == cleanUrl || a.SourceUrl.StartsWith(cleanUrl)); if (existing != null) { return existing; } - throw; + return article; } return article;