From 6017dabe9a1d495f3beba431604ae00923db3777 Mon Sep 17 00:00:00 2001 From: adimiko Date: Mon, 5 Feb 2024 05:25:11 +0100 Subject: [PATCH] Added MVP-1 --- Directory.Build.props | 8 ++ Directory.Packages.props | 19 +++++ source/TransactionContext.Postgres/Class1.cs | 6 -- .../TransactionContext.Postgres/Extensions.cs | 19 +++++ .../Internals/PostgresConnectionFactory.cs | 14 ++++ .../TransactionContext.Postgres.csproj | 8 ++ source/TransactionContext/Class1.cs | 6 -- .../Configurators/IDbProviderConfigurator.cs | 9 +++ source/TransactionContext/Extensions.cs | 20 +++++ .../IDbConnectionFactory.cs | 9 +++ .../TransactionContext/ITransactionContext.cs | 11 +++ .../Internals/DbProviderConfigurator.cs | 12 +++ .../Internals/InternalTransactionContext.cs | 79 +++++++++++++++++++ .../TransactionContext.csproj | 4 + 14 files changed, 212 insertions(+), 12 deletions(-) create mode 100644 Directory.Build.props create mode 100644 Directory.Packages.props delete mode 100644 source/TransactionContext.Postgres/Class1.cs create mode 100644 source/TransactionContext.Postgres/Extensions.cs create mode 100644 source/TransactionContext.Postgres/Internals/PostgresConnectionFactory.cs delete mode 100644 source/TransactionContext/Class1.cs create mode 100644 source/TransactionContext/Configurators/IDbProviderConfigurator.cs create mode 100644 source/TransactionContext/Extensions.cs create mode 100644 source/TransactionContext/IDbConnectionFactory.cs create mode 100644 source/TransactionContext/ITransactionContext.cs create mode 100644 source/TransactionContext/Internals/DbProviderConfigurator.cs create mode 100644 source/TransactionContext/Internals/InternalTransactionContext.cs diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..de8babf --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,8 @@ + + + + true + $(NoWarn);CS8604 + + + \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..2237e42 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,19 @@ + + + true + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/TransactionContext.Postgres/Class1.cs b/source/TransactionContext.Postgres/Class1.cs deleted file mode 100644 index 507d805..0000000 --- a/source/TransactionContext.Postgres/Class1.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace TransactionContext.Postgres; - -public class Class1 -{ - -} diff --git a/source/TransactionContext.Postgres/Extensions.cs b/source/TransactionContext.Postgres/Extensions.cs new file mode 100644 index 0000000..da788b3 --- /dev/null +++ b/source/TransactionContext.Postgres/Extensions.cs @@ -0,0 +1,19 @@ +using System.Data.Common; +using Microsoft.Extensions.DependencyInjection; +using Npgsql; +using TransactionContext.Configurators; +using TransactionContext.Postgres.Internals; + +namespace TransactionContext.Postgres +{ + public static class Extensions + { + public static void UsePostgres( + this IDbProviderConfigurator configurator, + string connectionString) + { + configurator.Services.AddSingleton(new PostgresConnectionFactory(connectionString)); + configurator.Services.AddScoped(); + } + } +} diff --git a/source/TransactionContext.Postgres/Internals/PostgresConnectionFactory.cs b/source/TransactionContext.Postgres/Internals/PostgresConnectionFactory.cs new file mode 100644 index 0000000..d6d4334 --- /dev/null +++ b/source/TransactionContext.Postgres/Internals/PostgresConnectionFactory.cs @@ -0,0 +1,14 @@ +using Npgsql; +using System.Data.Common; + +namespace TransactionContext.Postgres.Internals +{ + internal sealed class PostgresConnectionFactory : IDbConnectionFactory + { + private readonly string _connectionString; + + public PostgresConnectionFactory(string connectionString) => _connectionString = connectionString; + + public DbConnection Create() => new NpgsqlConnection(_connectionString); + } +} diff --git a/source/TransactionContext.Postgres/TransactionContext.Postgres.csproj b/source/TransactionContext.Postgres/TransactionContext.Postgres.csproj index fa71b7a..970ee6f 100644 --- a/source/TransactionContext.Postgres/TransactionContext.Postgres.csproj +++ b/source/TransactionContext.Postgres/TransactionContext.Postgres.csproj @@ -6,4 +6,12 @@ enable + + + + + + + + diff --git a/source/TransactionContext/Class1.cs b/source/TransactionContext/Class1.cs deleted file mode 100644 index 2194d29..0000000 --- a/source/TransactionContext/Class1.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace TransactionContext; - -public class Class1 -{ - -} diff --git a/source/TransactionContext/Configurators/IDbProviderConfigurator.cs b/source/TransactionContext/Configurators/IDbProviderConfigurator.cs new file mode 100644 index 0000000..c303f41 --- /dev/null +++ b/source/TransactionContext/Configurators/IDbProviderConfigurator.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace TransactionContext.Configurators +{ + public interface IDbProviderConfigurator + { + IServiceCollection Services { get; } + } +} diff --git a/source/TransactionContext/Extensions.cs b/source/TransactionContext/Extensions.cs new file mode 100644 index 0000000..8051890 --- /dev/null +++ b/source/TransactionContext/Extensions.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using TransactionContext.Configurators; +using TransactionContext.Internals; + +namespace TransactionContext +{ + public static class Extensions + { + public static void AddTransactionContext( + this IServiceCollection services, + Action configure) + { + var configuratior = new DbProviderConfigurator(services); + + configure(configuratior); + + services.AddScoped(); + } + } +} diff --git a/source/TransactionContext/IDbConnectionFactory.cs b/source/TransactionContext/IDbConnectionFactory.cs new file mode 100644 index 0000000..c188c70 --- /dev/null +++ b/source/TransactionContext/IDbConnectionFactory.cs @@ -0,0 +1,9 @@ +using System.Data.Common; + +namespace TransactionContext +{ + public interface IDbConnectionFactory + { + DbConnection Create(); + } +} diff --git a/source/TransactionContext/ITransactionContext.cs b/source/TransactionContext/ITransactionContext.cs new file mode 100644 index 0000000..fb7ac39 --- /dev/null +++ b/source/TransactionContext/ITransactionContext.cs @@ -0,0 +1,11 @@ +using System.Data; + +namespace TransactionContext +{ + public interface ITransactionContext + { + void Add(string sql, object? parameters = null, CommandType command = CommandType.Text); + + Task Commit(CancellationToken cancellationToken = default); + } +} diff --git a/source/TransactionContext/Internals/DbProviderConfigurator.cs b/source/TransactionContext/Internals/DbProviderConfigurator.cs new file mode 100644 index 0000000..cdf232f --- /dev/null +++ b/source/TransactionContext/Internals/DbProviderConfigurator.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.DependencyInjection; +using TransactionContext.Configurators; + +namespace TransactionContext.Internals +{ + internal sealed class DbProviderConfigurator : IDbProviderConfigurator + { + public IServiceCollection Services { get; private set; } + + internal DbProviderConfigurator(IServiceCollection services) => Services = services; + } +} diff --git a/source/TransactionContext/Internals/InternalTransactionContext.cs b/source/TransactionContext/Internals/InternalTransactionContext.cs new file mode 100644 index 0000000..1503056 --- /dev/null +++ b/source/TransactionContext/Internals/InternalTransactionContext.cs @@ -0,0 +1,79 @@ +using System.Data.Common; +using System.Data; + +namespace TransactionContext.Internals +{ + internal sealed class InternalTransactionContext : ITransactionContext + { + private readonly IDbConnectionFactory _connectionFactory; + + private readonly DbBatch _dbBatch; + + public InternalTransactionContext( + IDbConnectionFactory connectionFactory, + DbBatch dbBatch) + { + _connectionFactory = connectionFactory; + _dbBatch = dbBatch; + } + + public void Add(string sql, object? parameters = null, CommandType command = CommandType.Text) + { + var cmd = _dbBatch.CreateBatchCommand(); + cmd.CommandText = sql; + cmd.CommandType = command; + + if (parameters != null) + { + var properties = parameters.GetType().GetProperties(); + + foreach (var property in properties) + { + var parameter = cmd.CreateParameter(); + + parameter.ParameterName = property.Name; + parameter.Value = property.GetValue(parameters); + + cmd.Parameters.Add(parameter); + } + } + + _dbBatch.BatchCommands.Add(cmd); + } + + public async Task Commit(CancellationToken cancellationToken = default) + { + using (DbConnection connection = _connectionFactory.Create()) + { + await connection + .OpenAsync(cancellationToken) + .ConfigureAwait(false); + + using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)) + { + try + { + _dbBatch.Connection = connection; + _dbBatch.Transaction = transaction; + + await _dbBatch + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); + + await transaction + .CommitAsync(cancellationToken) + .ConfigureAwait(false); + } + catch (Exception) + { + await transaction + .RollbackAsync(cancellationToken) + .ConfigureAwait(false); + + throw; + } + } + } + } + } +} diff --git a/source/TransactionContext/TransactionContext.csproj b/source/TransactionContext/TransactionContext.csproj index fa71b7a..ab53c0d 100644 --- a/source/TransactionContext/TransactionContext.csproj +++ b/source/TransactionContext/TransactionContext.csproj @@ -6,4 +6,8 @@ enable + + + +