private static void CheckArguments(IScopedTransactionalDatabase database, Type dataType, object data) { if (database == null) { throw new ArgumentNullException(nameof(database)); } if (dataType == null) { throw new ArgumentNullException(nameof(dataType)); } if (data == null) { throw new ArgumentNullException(nameof(data)); } if (dataType.IsValueType) { throw new ArgumentException("The argument must be a reference type.", nameof(dataType)); } if (!dataType.IsAssignableFrom(data.GetType())) { throw new ArgumentException($"The specified data must be of type '{dataType.FullName}' or an assignable type."); } }
public static Task RemoveAsync(this IScopedTransactionalDatabase database, Type dataType, object data, CancellationToken cancellation = default) { CheckArguments(database, dataType, data); return(GetExtension(database).RemoveAsync(dataType, data, cancellation)); }
private static TransactionalDataStoreExt GetExtension(IScopedTransactionalDatabase database) { Assert(database != null); var result = _extensions.GetOrCreateValue(database); Assert(result != null); result.Initialize(database); return(result); }
public void Initialize(IScopedTransactionalDatabase database) { // Volatile read op if (_database != null) { return; } // Write _dataStore only if there is no data store present currently. var current = Interlocked.CompareExchange(ref _database, database, null); // If there was a data store present, it must be the same than the one, we wanted to write. Assert(current == null || ReferenceEquals(current, database)); }
public static Task RemoveAsync(this IScopedTransactionalDatabase database, object data, CancellationToken cancellation = default) { if (database == null) { throw new ArgumentNullException(nameof(database)); } if (data == null) { throw new ArgumentNullException(nameof(data)); } if (data is ValueType) { throw new ArgumentException("The argument must be a reference type.", nameof(data)); } return(GetExtension(database).RemoveAsync(data.GetType(), data, cancellation)); }
public async Task <bool> WriteToDatabaseAsync(IScopedTransactionalDatabase transactionalDatabase, CancellationToken cancellation) { // Write touched target metadata to database foreach (var(originalMetadata, touchedMetadata) in _targetMetadataCache.Values.Where(p => p.Touched)) { var comparandMetdata = await transactionalDatabase.GetAsync <ProjectionTargetMetadata>(p => p.Id == (originalMetadata ?? touchedMetadata).Id).FirstOrDefault(); if (!MatchesByRevision(originalMetadata, comparandMetdata)) { return(false); } if (touchedMetadata == null) { Assert(originalMetadata != null); await transactionalDatabase.RemoveAsync(originalMetadata, cancellation); } else { touchedMetadata.MetadataRevision = originalMetadata?.MetadataRevision ?? 1; await transactionalDatabase.StoreAsync(touchedMetadata, cancellation); } } // TODO: Do we have to check whether the targets were updated concurrently? foreach (var targetToUpdate in _targetsToUpdate) { await transactionalDatabase.StoreAsync(targetToUpdate, cancellation); } foreach (var targetToDelete in _targetsToDelete) { await transactionalDatabase.RemoveAsync(targetToDelete, cancellation); } return(true); }
private static async Task <(long bankAccountNo1, long bankAccountNo2)> CreateBankAccountsAsync(IScopedTransactionalDatabase transactionalStore) { _ba1AmountComparand = Rnd.Next(); _ba2AmountComparand = Rnd.Next(); var bankAccount1 = new BankAccount { Id = 1, Amount = _ba1AmountComparand }; var bankAccount2 = new BankAccount { Id = 2, Amount = _ba2AmountComparand }; try { await transactionalStore.StoreAsync(bankAccount1); await transactionalStore.StoreAsync(bankAccount2); await transactionalStore.TryCommitAsync(); } catch { await transactionalStore.RollbackAsync(); throw; } return(bankAccount1.Id, bankAccount2.Id); }
private static async Task OutputAsync(long bankAccountNo1, long bankAccountNo2, IScopedTransactionalDatabase transactionalStore) { BankAccount bankAccount1, bankAccount2; try { bankAccount1 = await transactionalStore.GetAsync <BankAccount>(p => p.Id == bankAccountNo1).FirstOrDefault(); bankAccount2 = await transactionalStore.GetAsync <BankAccount>(p => p.Id == bankAccountNo2).FirstOrDefault(); await transactionalStore.TryCommitAsync(); } catch { await transactionalStore.RollbackAsync(); throw; } await Console.Out.WriteLineAsync($"Account1 amount: {bankAccount1.Amount} should be {_ba1AmountComparand}"); await Console.Out.WriteLineAsync($"Account2 amount: {bankAccount2.Amount} should be {_ba2AmountComparand}"); await Console.Out.WriteLineAsync(); await Console.Out.WriteLineAsync(bankAccount1.Amount == _ba1AmountComparand && bankAccount2.Amount == _ba2AmountComparand? "OK" : "NOT OK"); }