Esempio n. 1
0
        public async Task GivenTheCurrentMigrations_WhenRunningThemInBothDirections_DatabaseIsCorrectlyMigrated()
        {
            // Arrange
            string databaseName =
                $"it--{nameof(GivenTheCurrentMigrations_WhenRunningThemInBothDirections_DatabaseIsCorrectlyMigrated)}";

            DbContextOptions <TodoDbContext> dbContextOptions = GetDbContextOptions(databaseName);

            await using TodoDbContext todoDbContext = new TodoDbContext(dbContextOptions);
            bool isMigrationSuccessful;

            try
            {
                await todoDbContext.Database.EnsureDeletedAsync();

                IMigrator databaseMigrator = todoDbContext.GetInfrastructure().GetRequiredService <IMigrator>();

                // Act
                await databaseMigrator.MigrateAsync();

                // Revert migrations by using a special migration identifier.
                // See more here: https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet#dotnet-ef-database-update.
                await databaseMigrator.MigrateAsync(BeforeFirstDatabaseMigration);

                await databaseMigrator.MigrateAsync();

                isMigrationSuccessful = true;
            }
            catch
            {
                isMigrationSuccessful = false;
            }
            finally
            {
                await todoDbContext.Database.EnsureDeletedAsync();
            }

            // Assert
            isMigrationSuccessful.Should().BeTrue("migrations should work in both directions, up and down");
        }
        public async Task SaveChanges_WhenModifyingSameEntityUsingTwoConcurrentTransactions_ThrowsException()
        {
            // Arrange
            string databaseName =
                $"it--{nameof(SaveChanges_WhenModifyingSameEntityUsingTwoConcurrentTransactions_ThrowsException)}";
            DbContextOptions <TodoDbContext> dbContextOptions = GetDbContextOptions(databaseName);

            await using TodoDbContext firstTodoDbContext = new TodoDbContext(dbContextOptions);
            IMigrator databaseMigrator = firstTodoDbContext.GetInfrastructure().GetRequiredService <IMigrator>();
            await databaseMigrator.MigrateAsync();

            try
            {
                string name = "ConcurrentlyAccessedTodoItem";

                TodoItem todoItem = new TodoItem(name, "it")
                {
                    IsComplete = false,
                };

                await firstTodoDbContext.TodoItems.AddAsync(todoItem);

                await firstTodoDbContext.SaveChangesAsync();

                await using IDbContextTransaction firstTransaction =
                                await firstTodoDbContext.Database.BeginTransactionAsync();

                TodoItem todoItemFromFirstTransaction =
                    await firstTodoDbContext.TodoItems.FirstAsync(x => x.Name == name);

                todoItemFromFirstTransaction.IsComplete    = true;
                todoItemFromFirstTransaction.LastUpdatedBy = Guid.NewGuid().ToString("N");
                todoItemFromFirstTransaction.LastUpdatedOn = DateTime.UtcNow;

                await using TodoDbContext secondTodoDbContext       = new TodoDbContext(dbContextOptions);
                await using IDbContextTransaction secondTransaction =
                                await secondTodoDbContext.Database.BeginTransactionAsync();

                TodoItem todoItemFromSecondTransaction =
                    await secondTodoDbContext.TodoItems.FirstAsync(x => x.Name == name);

                todoItemFromSecondTransaction.IsComplete    = false;
                todoItemFromSecondTransaction.LastUpdatedBy = Guid.NewGuid().ToString("N");
                todoItemFromSecondTransaction.LastUpdatedOn = DateTime.UtcNow;

                await firstTodoDbContext.SaveChangesAsync();

                await firstTransaction.CommitAsync();

                // Act
                Func <Task> saveChangesAsyncCall = async() =>
                {
                    // ReSharper disable AccessToDisposedClosure
                    await secondTodoDbContext.SaveChangesAsync();

                    await secondTransaction.CommitAsync();

                    // ReSharper restore AccessToDisposedClosure
                };

                // Assert
                saveChangesAsyncCall.Should()
                .ThrowExactly <DbUpdateConcurrencyException>(
                    "2 transactions were concurrently modifying the same entity");
            }
            finally
            {
                await firstTodoDbContext.Database.EnsureDeletedAsync();
            }
        }