Skip to content

Commit 8b19e1f

Browse files
authored
Merge pull request #265 from baoduy/dev
public savechanges with handler
2 parents b74dbcf + 775b06d commit 8b19e1f

File tree

5 files changed

+69
-5
lines changed

5 files changed

+69
-5
lines changed

src/DKNet.FW.sln.DotSettings.user

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,12 +588,17 @@
588588
<Project Location="/Users/steven/_CODE/DRUNK/DKNet/src" Presentation="<SlimBus>" />
589589
</Or>
590590
&lt;/SessionState&gt;</s:String>
591-
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=741f3bef_002D9e13_002D4160_002D8efd_002D6460b3b44d61/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &amp;lt;SlimBus&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
591+
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=741f3bef_002D9e13_002D4160_002D8efd_002D6460b3b44d61/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="All tests from &amp;lt;SlimBus&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
592592
&lt;Project Location="/Users/steven/_CODE/DRUNK/DKNet/src" Presentation="&amp;lt;SlimBus&amp;gt;" /&gt;
593593
&lt;/SessionState&gt;</s:String>
594594
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=964034e5_002Dde7d_002D4983_002D9106_002D426b33d8b8f6/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &amp;lt;SlimBus&amp;gt;\&amp;lt;SlimBus.Extensions.Tests&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
595595
&lt;Project Location="/Users/steven/_CODE/DRUNK/DKNet/src/SlimBus/SlimBus.Extensions.Tests" Presentation="&amp;lt;SlimBus&amp;gt;\&amp;lt;SlimBus.Extensions.Tests&amp;gt;" /&gt;
596596
&lt;/SessionState&gt;</s:String>
597+
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=d48a29df_002D0ba6_002D4810_002D9bc0_002Dd5077a354521/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="SlimBusEfCoreSetupTests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
598+
&lt;TestAncestor&gt;
599+
&lt;TestId&gt;xUnit::BC6A92F4-BE7F-405F-87A1-43A73D3CCD29::net10.0::SlimBus.Extensions.Tests.SlimBusEfCoreSetupTests&lt;/TestId&gt;
600+
&lt;/TestAncestor&gt;
601+
&lt;/SessionState&gt;</s:String>
597602

598603

599604

src/SlimBus/DKNet.SlimBus.Extensions/Interceptors/EfAutoSavePostInterceptor.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using DKNet.EfCore.Extensions.Extensions;
22
using FluentResults;
33
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.Extensions.DependencyInjection;
45
using Microsoft.Extensions.Logging;
56
using SlimMessageBus;
67
using SlimMessageBus.Host.Interceptor;
@@ -47,7 +48,8 @@ request is Fluents.Queries.IWitPageResponse<TResponse> ||
4748
return response;
4849
}
4950

50-
var exceptionHandler = serviceProvider.GetService(typeof(IEfCoreExceptionHandler)) as IEfCoreExceptionHandler;
51+
//Global exception handling.
52+
var exceptionHandler = serviceProvider.GetService<IEfCoreExceptionHandler>();
5153
var dbContexts = EfAutoSavePostProcessorRegistration.DbContextTypes
5254
.Select(serviceProvider.GetService).OfType<DbContext>().ToArray();
5355

@@ -56,11 +58,15 @@ request is Fluents.Queries.IWitPageResponse<TResponse> ||
5658

5759
foreach (var db in dbContexts.Where(db => db.ChangeTracker.HasChanges()))
5860
{
61+
//Context level exception handling
62+
var contextExceptionHandler =
63+
serviceProvider.GetKeyedService<IEfCoreExceptionHandler>(db.GetType().FullName);
5964
var dbContextTypeName = db.GetType().Name;
6065
logger.LogDebug("DbContext {DbContextType} has changes. Saving...", dbContextTypeName);
6166

6267
await db.AddNewEntitiesFromNavigations(context.CancellationToken).ConfigureAwait(false);
63-
await db.SaveChangesWithConcurrencyHandlingAsync(exceptionHandler, context.CancellationToken)
68+
await db.SaveChangesWithConcurrencyHandlingAsync(contextExceptionHandler ?? exceptionHandler,
69+
context.CancellationToken)
6470
.ConfigureAwait(false);
6571

6672
logger.LogDebug("DbContext {DbContextType} changes saved.", dbContextTypeName);

src/SlimBus/DKNet.SlimBus.Extensions/Interceptors/EfSaveChangesExtension.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace DKNet.SlimBus.Extensions.Interceptors;
44

5-
internal static class EfSaveChangesExtension
5+
public static class EfSaveChangesExtension
66
{
77
#region Methods
88

@@ -37,4 +37,4 @@ public static async Task<int> SaveChangesWithConcurrencyHandlingAsync(
3737
}
3838

3939
#endregion
40-
}
40+
}

src/SlimBus/DKNet.SlimBus.Extensions/SlimBusEfCoreSetup.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ public IServiceCollection AddSlimBusEventPublisher<TDbContext>()
3636
return serviceCollection;
3737
}
3838

39+
/// <summary>
40+
/// Registers a custom EF Core exception handler for the specified <typeparamref name="TDbContext" />.
41+
/// </summary>
42+
/// <typeparam name="TDbContext"></typeparam>
43+
/// <typeparam name="TExceptionHandler"></typeparam>
44+
/// <returns></returns>
45+
public IServiceCollection AddSlimBusEfCoreExceptionHandler<TDbContext, TExceptionHandler>()
46+
where TDbContext : DbContext
47+
where TExceptionHandler : class, IEfCoreExceptionHandler =>
48+
serviceCollection.AddKeyedTransient<IEfCoreExceptionHandler, TExceptionHandler>(typeof(TDbContext)
49+
.FullName);
50+
3951
/// <summary>
4052
/// Adds SlimMessageBus and EF Core integration services required for auto-saving the DbContext after
4153
/// request handlers run. Registers the <see cref="EfAutoSavePostInterceptor{TRequest,TResponse}" />
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// <copyright file="SlimBusEfCoreSetupTests.cs" company="https://drunkcoding.net">
2+
// Copyright (c) 2025 Steven Hoang. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE in the project root for license information.
4+
// </copyright>
5+
6+
using DKNet.SlimBus.Extensions.Interceptors;
7+
8+
namespace SlimBus.Extensions.Tests
9+
{
10+
/// <summary>
11+
/// Unit tests for SlimBusEfCoreSetup extension methods.
12+
/// </summary>
13+
public class SlimBusEfCoreSetupTests
14+
{
15+
/// <summary>
16+
/// Verifies AddSlimBusEfCoreExceptionHandler registers the correct handler keyed by DbContext type.
17+
/// </summary>
18+
[Fact]
19+
public void AddSlimBusEfCoreExceptionHandler_RegistersKeyedHandler_CanResolveByKey()
20+
{
21+
// Arrange
22+
var services = new ServiceCollection();
23+
services.AddSlimBusEfCoreExceptionHandler<TestDbContext, TestExceptionHandler>();
24+
var provider = services.BuildServiceProvider();
25+
var key = typeof(TestDbContext).FullName;
26+
27+
// Act
28+
var handler = provider.GetKeyedService<IEfCoreExceptionHandler>(key!);
29+
30+
// Assert
31+
handler.ShouldNotBeNull();
32+
handler.ShouldBeOfType<TestExceptionHandler>();
33+
}
34+
35+
private class TestExceptionHandler : IEfCoreExceptionHandler
36+
{
37+
public Task<EfConcurrencyResolution> HandlingAsync(DbContext context, DbUpdateConcurrencyException exception, CancellationToken cancellationToken = default)
38+
=> Task.FromResult(EfConcurrencyResolution.IgnoreChanges);
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)