mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-12 20:01:56 +08:00
153 lines
4.4 KiB
C#
153 lines
4.4 KiB
C#
using System.Globalization;
|
|
using Microsoft.Extensions.Options;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Bson.Serialization;
|
|
using MongoDB.Bson.Serialization.Conventions;
|
|
using MongoDB.Bson.Serialization.Serializers;
|
|
using MongoDB.Driver;
|
|
|
|
namespace BuildingBlocks.Mongo;
|
|
|
|
// https://www.thecodebuzz.com/mongodb-repository-implementation-unit-testing-net-core-example/
|
|
|
|
public class MongoDbContext : IMongoDbContext
|
|
{
|
|
public IClientSessionHandle? Session { get; set; }
|
|
public IMongoDatabase Database { get; }
|
|
public IMongoClient MongoClient { get; }
|
|
protected readonly IList<Func<Task>> _commands;
|
|
private static readonly bool _isSerializerRegisterd;
|
|
|
|
static MongoDbContext()
|
|
{
|
|
BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));
|
|
}
|
|
|
|
public MongoDbContext(IOptions<MongoOptions> options)
|
|
{
|
|
RegisterConventions();
|
|
|
|
MongoClient = new MongoClient(options.Value.ConnectionString);
|
|
var databaseName = options.Value.DatabaseName;
|
|
Database = MongoClient.GetDatabase(databaseName);
|
|
|
|
// Every command will be stored and it'll be processed at SaveChanges
|
|
_commands = new List<Func<Task>>();
|
|
}
|
|
|
|
private static void RegisterConventions()
|
|
{
|
|
ConventionRegistry.Register(
|
|
"conventions",
|
|
new ConventionPack
|
|
{
|
|
new CamelCaseElementNameConvention(),
|
|
new IgnoreExtraElementsConvention(true),
|
|
new EnumRepresentationConvention(BsonType.String),
|
|
new IgnoreIfDefaultConvention(false),
|
|
new ImmutablePocoConvention()
|
|
}, _ => true);
|
|
}
|
|
|
|
public IMongoCollection<T> GetCollection<T>(string? name = null)
|
|
{
|
|
return Database.GetCollection<T>(name ?? typeof(T).Name.ToLower(CultureInfo.CurrentCulture));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
while (Session is { IsInTransaction: true })
|
|
Thread.Sleep(TimeSpan.FromMilliseconds(100));
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var result = _commands.Count;
|
|
|
|
using (Session = await MongoClient.StartSessionAsync(cancellationToken: cancellationToken))
|
|
{
|
|
Session.StartTransaction();
|
|
|
|
try
|
|
{
|
|
var commandTasks = _commands.Select(c => c());
|
|
|
|
await Task.WhenAll(commandTasks);
|
|
|
|
await Session.CommitTransactionAsync(cancellationToken);
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
await Session.AbortTransactionAsync(cancellationToken);
|
|
_commands.Clear();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
_commands.Clear();
|
|
return result;
|
|
}
|
|
|
|
public async Task BeginTransactionAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
Session = await MongoClient.StartSessionAsync(cancellationToken: cancellationToken);
|
|
Session.StartTransaction();
|
|
}
|
|
|
|
public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
if (Session is { IsInTransaction: true })
|
|
await Session.CommitTransactionAsync(cancellationToken);
|
|
|
|
Session?.Dispose();
|
|
}
|
|
|
|
public async Task RollbackTransaction(CancellationToken cancellationToken = default)
|
|
{
|
|
await Session?.AbortTransactionAsync(cancellationToken)!;
|
|
}
|
|
|
|
public void AddCommand(Func<Task> func)
|
|
{
|
|
_commands.Add(func);
|
|
}
|
|
|
|
public async Task ExecuteTransactionalAsync(Func<Task> action, CancellationToken cancellationToken = default)
|
|
{
|
|
await BeginTransactionAsync(cancellationToken);
|
|
try
|
|
{
|
|
await action();
|
|
|
|
await CommitTransactionAsync(cancellationToken);
|
|
}
|
|
catch
|
|
{
|
|
await RollbackTransaction(cancellationToken);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public async Task<T> ExecuteTransactionalAsync<T>(
|
|
Func<Task<T>> action,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await BeginTransactionAsync(cancellationToken);
|
|
try
|
|
{
|
|
var result = await action();
|
|
|
|
await CommitTransactionAsync(cancellationToken);
|
|
|
|
return result;
|
|
}
|
|
catch
|
|
{
|
|
await RollbackTransaction(cancellationToken);
|
|
throw;
|
|
}
|
|
}
|
|
}
|