public DbUserAccountRepository(DbContextOptions options) { _context = new DbUserAccountContext(options); }
public async Task CreateAccountUseCreditDestroyAccount() { Init(); IRepository<string, DbUserAccount> userAccountRespository = _UserAccountRepositoryFactory.Create(); using (DbUserAccountContext ctx = new DbUserAccountContext(dbOptions)) { ctx.Database.ExecuteSqlCommand("DELETE FROM DbUserAccount"); ctx.Database.ExecuteSqlCommand("DELETE FROM DbUserAccountCreditBalance"); } string username = "******"; string password = "******"; // Make sure that LoadAsync retursn null for an account that doesn't exist yet. DbUserAccount accountThatShouldNotExist = await userAccountRespository.LoadAsync(username); Assert.Null(accountThatShouldNotExist); // Create an add a new account to the database DbUserAccount newAccount = userAccountController.Create(username, password); newAccount.CreditLimit = 1d; await userAccountRespository.AddAsync(newAccount); // Load that account back in DbUserAccount reloadedAccount = await userAccountRespository.LoadAsync(username); Assert.NotNull(reloadedAccount); // Try to use half of the credit limit double credit = await userAccountController.TryGetCreditAsync(reloadedAccount, 0.5); Assert.Equal(credit, 0.5d); // Try to use 100 times the credit limit of 1, only to receive ~.5 back // (you'll get a tiny amount more as the consumed credit has decayed with time) double moreCredit = await userAccountController.TryGetCreditAsync(reloadedAccount, 1000); Assert.InRange(moreCredit, 0.5d, 0.51d); // Clean up using (DbUserAccountContext context = new DbUserAccountContext(dbOptions)) { DbUserAccount account = context.DbUserAccounts.FirstOrDefault(a => a.UsernameOrAccountId == username); Assert.NotNull(account); if (account != null) context.DbUserAccounts.Remove(account); await context.SaveChangesAsync(); DbUserAccountCreditBalance balance = context.DbUserAccountCreditBalances.FirstOrDefault(a => a.DbUserAccountId == username); if (balance != null) { context.DbUserAccountCreditBalances.Remove(balance); await context.SaveChangesAsync(); } } }
public DbUserAccountRepository() { _context = new DbUserAccountContext(); }
public override async Task <double> TryGetCreditAsync( DbUserAccount userAccount, double amountRequested, DateTime?timeOfRequestUtc = null, CancellationToken cancellationToken = default(CancellationToken)) { if (Double.IsNaN(amountRequested) || amountRequested <= 0) { // You can't request a negative amount and requesting nothing is free return(0); } DateTime timeOfRequestOrNowUtc = timeOfRequestUtc ?? DateTime.Now; double creditRetrieved = 0; using (var context = new DbUserAccountContext(DbOptions)) { using (var dbContextTransaction = await context.Database.BeginTransactionAsync(cancellationToken)) { bool rolledBackDueToConcurrencyException = false; do { try { DbUserAccountCreditBalance balance = await context.DbUserAccountCreditBalances.Where(b => b.DbUserAccountId == userAccount.DbUserAccountId) .FirstOrDefaultAsync(cancellationToken: cancellationToken); if (balance == null) { creditRetrieved = Math.Min(amountRequested, userAccount.CreditLimit); double amountRemaining = userAccount.CreditLimit - creditRetrieved; context.DbUserAccountCreditBalances.Add( new DbUserAccountCreditBalance() { DbUserAccountId = userAccount.DbUserAccountId, ConsumedCreditsLastUpdatedUtc = timeOfRequestOrNowUtc, ConsumedCreditsLastValue = amountRemaining }); } else { double amountAvailable = Math.Max(0, userAccount.CreditLimit - DecayingDouble.Decay(balance.ConsumedCreditsLastValue, userAccount.CreditHalfLife, balance.ConsumedCreditsLastUpdatedUtc, timeOfRequestOrNowUtc)); if (amountAvailable > 0) { creditRetrieved = Math.Min(amountRequested, amountAvailable); } double amountRemaining = amountAvailable - creditRetrieved; balance.ConsumedCreditsLastValue = amountRemaining; balance.ConsumedCreditsLastUpdatedUtc = timeOfRequestOrNowUtc; } await context.SaveChangesAsync(cancellationToken); dbContextTransaction.Commit(); } catch (DbUpdateConcurrencyException) { dbContextTransaction.Rollback(); rolledBackDueToConcurrencyException = true; } } while (rolledBackDueToConcurrencyException); } } return(creditRetrieved); }