public ProjectionEngine(IProjector projector, IFilterableDatabase database, ITransactionalDatabase transactionalDatabase, IServiceProvider serviceProvider, ILogger <ProjectionEngine> logger = default) { if (projector == null) { throw new ArgumentNullException(nameof(projector)); } if (database == null) { throw new ArgumentNullException(nameof(database)); } if (transactionalDatabase == null) { throw new ArgumentNullException(nameof(transactionalDatabase)); } if (serviceProvider == null) { throw new ArgumentNullException(nameof(serviceProvider)); } _projector = projector; _database = database; _transactionalDatabase = transactionalDatabase; _serviceProvider = serviceProvider; _logger = logger; }
public DataStore(ITransactionalDatabase database) { if (database == null) { throw new ArgumentNullException(nameof(database)); } _database = database; }
public static IAsyncEnumerable <TData> UnconditionalReadAsync <TData>(this ITransactionalDatabase database, Expression <Func <TData, bool> > predicate, CancellationToken cancellation = default) where TData : class { if (database == null) { throw new ArgumentNullException(nameof(database)); } if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); } async Task <IEnumerable <TData> > PerformReadAsync() { IEnumerable <TData> result; using (var transactionalDatabase = database.CreateScope()) { do { try { // We have to load all data to memory. // Otherwise the data would be queried lazily by the caller after the transaction ended. result = await transactionalDatabase.GetAsync(predicate, cancellation); if (await transactionalDatabase.TryCommitAsync(cancellation)) { break; } } catch (TransactionAbortedException) { } catch (Exception) { // TODO: Log throw; } }while (true); } return(result); } return(PerformReadAsync().ToAsyncEnumerable()); }
public static async Task UnconditionalWriteAsync(this ITransactionalDatabase database, Func <IScopedTransactionalDatabase, CancellationToken, Task> operation, CancellationToken cancellation = default) { if (database == null) { throw new ArgumentNullException(nameof(database)); } if (operation == null) { throw new ArgumentNullException(nameof(operation)); } using (var transactionalDatabase = database.CreateScope()) { do { try { await operation(transactionalDatabase, cancellation); if (await transactionalDatabase.TryCommitAsync(cancellation)) { break; } } catch (TransactionAbortedException) { } catch (Exception) { // TODO: Log throw; } }while (true); } }
private static async Task TransferAsync(long bankAccountNo1, long bankAccountNo2, ITransactionalDatabase database) { var transferAmount = Rnd.Next(2001) - 1000; using (var transactionalStore = database.CreateScope()) { do { try { var bankAccount1 = await transactionalStore.GetAsync <BankAccount>(p => p.Id == bankAccountNo1).FirstOrDefault(); var bankAccount2 = await transactionalStore.GetAsync <BankAccount>(p => p.Id == bankAccountNo2).FirstOrDefault(); bankAccount1.Amount -= transferAmount; bankAccount2.Amount += transferAmount; await transactionalStore.StoreAsync(bankAccount1); await transactionalStore.StoreAsync(bankAccount2); } catch (TransactionAbortedException) { continue; } catch { await transactionalStore.RollbackAsync(); throw; } }while (!await transactionalStore.TryCommitAsync()); } Interlocked.Add(ref _ba1AmountComparand, -transferAmount); Interlocked.Add(ref _ba2AmountComparand, transferAmount); }