diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/ClickhouseDbConnectionFactory.cs b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/ClickhouseDbConnectionFactory.cs
index e2e43b7..461a19e 100644
--- a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/ClickhouseDbConnectionFactory.cs
+++ b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/ClickhouseDbConnectionFactory.cs
@@ -1,13 +1,16 @@
using System.Data;
using ClickHouse.Client;
using Cnblogs.Architecture.Ddd.Infrastructure.Dapper;
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper.Clickhouse;
namespace Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse;
///
/// Clickhouse connection factory.
///
-public class ClickhouseDbConnectionFactory(IClickHouseDataSource dataSource) : IDbConnectionFactory
+/// The this connection factory belongs to.
+public class ClickhouseDbConnectionFactory(IClickHouseDataSource dataSource) : IDbConnectionFactory
+ where TContext : ClickhouseDapperContext
{
///
public IDbConnection CreateDbConnection()
diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/DapperConfigurationBuilderExtension.cs b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/DapperConfigurationBuilderExtension.cs
index bf5d921..3ae00f5 100644
--- a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/DapperConfigurationBuilderExtension.cs
+++ b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse/DapperConfigurationBuilderExtension.cs
@@ -1,3 +1,4 @@
+using ClickHouse.Client;
using Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse;
using Cnblogs.Architecture.Ddd.Infrastructure.Dapper.Clickhouse;
using Microsoft.Extensions.DependencyInjection;
@@ -21,8 +22,11 @@ public static void UseClickhouse(
string connectionString)
where TContext : ClickhouseDapperContext
{
- builder.UseDbConnectionFactory();
- builder.Services.AddClickHouseDataSource(connectionString);
+ var contextName = typeof(TContext).Name;
+ builder.UseDbConnectionFactory(sp
+ => new ClickhouseDbConnectionFactory(
+ sp.GetRequiredKeyedService(contextName)));
+ builder.Services.AddClickHouseDataSource(connectionString, serviceKey: contextName);
builder.Services.AddSingleton(new ClickhouseContextOptions(connectionString));
builder.Services.Configure(x => x.Add());
builder.Services.AddHostedService();
diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj
index 89a9658..b0b49aa 100644
--- a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj
+++ b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/DapperConfigurationBuilder.cs b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/DapperConfigurationBuilder.cs
index 62a3542..6673de2 100644
--- a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/DapperConfigurationBuilder.cs
+++ b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/DapperConfigurationBuilder.cs
@@ -36,6 +36,19 @@ public void UseDbConnectionFactory(TFactory factory)
c => c.AddDbConnectionFactory(_dapperContextTypeName, typeof(TFactory)));
}
+ ///
+ /// Add by .
+ ///
+ /// The object initializer.
+ /// The type of the factory.
+ public void UseDbConnectionFactory(Func implementationFactory)
+ where TFactory : class
+ {
+ Services.AddSingleton(implementationFactory);
+ Services.Configure(
+ c => c.AddDbConnectionFactory(_dapperContextTypeName, typeof(TFactory)));
+ }
+
///
/// Add as and get instance from DI when used.
///
diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/ServiceCollectionInjector.cs b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/ServiceCollectionInjector.cs
index f5a3080..b8d4bb2 100644
--- a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/ServiceCollectionInjector.cs
+++ b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper/ServiceCollectionInjector.cs
@@ -18,6 +18,12 @@ public static class ServiceCollectionInjector
public static DapperConfigurationBuilder AddDapperContext(this IServiceCollection services)
where TContext : DapperContext
{
+ var alreadyAdded = services.Any(s => s.ServiceType == typeof(TContext));
+ if (alreadyAdded)
+ {
+ throw new InvalidOperationException($"Dapper context with name {typeof(TContext).Name} already added");
+ }
+
services.AddScoped();
return new DapperConfigurationBuilder(services);
}
diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj
index 26ad41f..756e73b 100644
--- a/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj
+++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj b/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj
index 06072a5..18fdb2f 100644
--- a/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj
+++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj
index aae480f..535e7de 100644
--- a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj
+++ b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj
@@ -1,7 +1,7 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
@@ -9,7 +9,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
diff --git a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj
index 1f86a30..3406913 100644
--- a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj
+++ b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj
@@ -3,7 +3,7 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
@@ -15,6 +15,7 @@
+
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/ClickhouseDependencyInjectorTests.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/ClickhouseDependencyInjectorTests.cs
new file mode 100644
index 0000000..a02e036
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/ClickhouseDependencyInjectorTests.cs
@@ -0,0 +1,47 @@
+using ClickHouse.Client;
+using Cnblogs.Architecture.Ddd.Cqrs.Dapper;
+using Cnblogs.Architecture.Ddd.Cqrs.Dapper.Clickhouse;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class ClickhouseDependencyInjectorTests
+{
+ [Fact]
+ public void UseClickhouse_InjectSingle_Injected()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddDapperContext().UseClickhouse("HOST=clickhouse");
+ var serviceProvider = services.BuildServiceProvider();
+ var dbContext = serviceProvider.GetRequiredService();
+ var clickhouseDataSource =
+ serviceProvider.GetRequiredKeyedService(nameof(TestClickhouseDapperContext));
+
+ // Assert
+ Assert.NotNull(dbContext);
+ Assert.NotNull(clickhouseDataSource);
+ }
+
+ [Fact]
+ public void UseClickhouse_InjectMultiple_Injected()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddDapperContext().UseClickhouse("HOST=clickhouse");
+ services.AddDapperContext().UseClickhouse("HOST=alterclickhouse");
+ var serviceProvider = services.BuildServiceProvider();
+ var dbContext = serviceProvider.GetRequiredService();
+ var alterContext = serviceProvider.GetRequiredService();
+ var dbFactory = dbContext.Factory;
+ var alterFactory = alterContext.Factory;
+
+ // Assert
+ Assert.True(dbFactory is ClickhouseDbConnectionFactory);
+ Assert.True(alterFactory is ClickhouseDbConnectionFactory);
+ }
+}
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/DapperConfigurationBuilderTests.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/DapperConfigurationBuilderTests.cs
new file mode 100644
index 0000000..f506cbf
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/DapperConfigurationBuilderTests.cs
@@ -0,0 +1,63 @@
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class DapperConfigurationBuilderTests
+{
+ [Fact]
+ public void UseDbConnectionFactory_Instance_AddInstance()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+ var factory = new TestDbConnectionFactory();
+
+ // Act
+ services.AddDapperContext().UseDbConnectionFactory(factory);
+ var serviceProvider = services.BuildServiceProvider();
+ var fetchedFactory = serviceProvider.GetService();
+ var collection = serviceProvider.GetRequiredService>().Value;
+
+ // Assert
+ Assert.Equal(factory, fetchedFactory);
+ Assert.Equal(typeof(TestDbConnectionFactory), collection.GetFactory(nameof(TestDapperContext)));
+ }
+
+ [Fact]
+ public void UseDbConnectionFactory_Type_AddType()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddDapperContext().UseDbConnectionFactory();
+ var serviceProvider = services.BuildServiceProvider();
+ var fetchedFactory = serviceProvider.GetService();
+ var collection = serviceProvider.GetRequiredService>().Value;
+
+ // Assert
+ Assert.NotNull(fetchedFactory);
+ Assert.Equal(typeof(TestDbConnectionFactory), collection.GetFactory(nameof(TestDapperContext)));
+ }
+
+ [Fact]
+ public void UseDbConnectionFactory_Func_AddFunc()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+ var factory = new TestDbConnectionFactory();
+ services.AddKeyedSingleton("test", factory);
+
+ // Act
+ services.AddDapperContext()
+ .UseDbConnectionFactory(sp => sp.GetRequiredKeyedService("test"));
+ var serviceProvider = services.BuildServiceProvider();
+ var fetchedFactory = serviceProvider.GetRequiredService();
+ var collection = serviceProvider.GetRequiredService>().Value;
+
+ // Assert
+ Assert.Equal(factory, fetchedFactory);
+ Assert.Equal(typeof(TestDbConnectionFactory), collection.GetFactory(nameof(TestDapperContext)));
+ }
+}
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/DapperServiceCollectionInjectorTests.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/DapperServiceCollectionInjectorTests.cs
new file mode 100644
index 0000000..0219564
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/DapperServiceCollectionInjectorTests.cs
@@ -0,0 +1,32 @@
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class DapperServiceCollectionInjectorTests
+{
+ [Fact]
+ public void AddDapperContext_AddContext_Success()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddDapperContext();
+
+ // Assert
+ Assert.Contains(services, s => s.ServiceType == typeof(TestDapperContext));
+ }
+
+ [Fact]
+ public void AddDapperContext_AddSameContextMultipleTimes_ThrowsException()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddDapperContext();
+
+ // Assert
+ Assert.Throws(() => services.AddDapperContext());
+ }
+}
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestAlterClickhouseDapperContext.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestAlterClickhouseDapperContext.cs
new file mode 100644
index 0000000..ea0b88f
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestAlterClickhouseDapperContext.cs
@@ -0,0 +1,20 @@
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper;
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper.Clickhouse;
+using Microsoft.Extensions.Options;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class TestAlterClickhouseDapperContext(
+ IOptions dbConnectionFactoryCollection,
+ ClickhouseContextOptions options,
+ IServiceProvider serviceProvider)
+ : ClickhouseDapperContext(dbConnectionFactoryCollection, options, serviceProvider)
+{
+ ///
+ protected override void ConfigureModels(ClickhouseModelCollectionBuilder builder)
+ {
+ // ignore
+ }
+
+ public IDbConnectionFactory Factory => DbConnectionFactory;
+}
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestClickhouseDapperContext.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestClickhouseDapperContext.cs
new file mode 100644
index 0000000..ccc16cc
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestClickhouseDapperContext.cs
@@ -0,0 +1,22 @@
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper;
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper.Clickhouse;
+using Microsoft.Extensions.Options;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class TestClickhouseDapperContext(
+ IOptions dbConnectionFactoryCollection,
+ ClickhouseContextOptions options,
+ IServiceProvider serviceProvider)
+ : ClickhouseDapperContext(dbConnectionFactoryCollection, options, serviceProvider)
+{
+ public bool ConfigureModelsCalled { get; set; }
+
+ public IDbConnectionFactory Factory => DbConnectionFactory;
+
+ ///
+ protected override void ConfigureModels(ClickhouseModelCollectionBuilder builder)
+ {
+ ConfigureModelsCalled = true;
+ }
+}
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestDapperContext.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestDapperContext.cs
new file mode 100644
index 0000000..1bf36b5
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestDapperContext.cs
@@ -0,0 +1,15 @@
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper;
+using Microsoft.Extensions.Options;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class TestDapperContext : DapperContext
+{
+ ///
+ public TestDapperContext(
+ IOptions dbConnectionFactoryCollection,
+ IServiceProvider sp)
+ : base(dbConnectionFactoryCollection, sp)
+ {
+ }
+}
diff --git a/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestDbConnectionFactory.cs b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestDbConnectionFactory.cs
new file mode 100644
index 0000000..7fca503
--- /dev/null
+++ b/test/Cnblogs.Architecture.UnitTests/Cqrs/Dapper/TestDbConnectionFactory.cs
@@ -0,0 +1,14 @@
+using System.Data;
+using Cnblogs.Architecture.Ddd.Infrastructure.Dapper;
+using NSubstitute;
+
+namespace Cnblogs.Architecture.UnitTests.Cqrs.Dapper;
+
+public class TestDbConnectionFactory : IDbConnectionFactory
+{
+ ///
+ public IDbConnection CreateDbConnection()
+ {
+ return Substitute.For();
+ }
+}