예제 #1
0
 public static Task MigrateAsync(this DbContext v, string migration = "")
 {
     if (string.IsNullOrEmpty(migration))
     {
         return(v.Database.MigrateAsync());
     }
     else
     {
         IMigrator migrator = v.GetInfrastructure().GetService <IMigrator>();
         return(migrator.MigrateAsync(migration));
     }
 }
예제 #2
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");
        }
        /// <summary>
        /// Applies pending migrations, if any.
        /// </summary>
        /// <param name="ep">The IEndPointConfiguration whose properties will be used as keys.</param>
        /// <returns>A list of names of migrations that were applied.</returns>
        public virtual async Task <List <string> > ApplyMigrations(IEndPointConfiguration endPoint)
        {
            DbContext            context         = resolver.ResolveMigrationContext(endPoint);
            IDatabaseInitializer dataInitializer = resolver.ResolveDatabaseInitializer(endPoint);

            List <string> migrations = (await context.Database.GetPendingMigrationsAsync()).ToList();
            IMigrator     migrator   = context.Database.GetService <IMigrator>();

            foreach (string migrationName in migrations)
            {
                await migrator.MigrateAsync(migrationName);

                if (dataInitializer != null)
                {
                    await dataInitializer.Seed(migrationName);
                }
            }
            return(migrations);
        }
        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();
            }
        }
        public async Task <MigratorHarness <TContext> > TargetMigrationAsync(string migrationName)
        {
            await _migrator.MigrateAsync(migrationName);

            return(this);
        }