Hi,
I am trying to trigger EF migrations using Dtabase.Migrate.
I have used this code as a reference: <a class="postlink" href="https://stackoverflow.com/questions/45123604/ef-core-migration-with-aspnetboilerplate-where-to-trigger-context-database-migra">https://stackoverflow.com/questions/451 ... base-migra</a>
But I think migration should take place before seeding - seeding may need new schema!
Currently I do this:
public class MyEntityFrameworkCoreModule : AbpModule
{
/* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */
public bool SkipDbContextRegistration { get; set; }
public bool SkipDbSeed { get; set; }
public override void PreInitialize()
{
if (!SkipDbContextRegistration)
{
Configuration.Modules.AbpEfCore().AddDbContext<MyDbContext>(options =>
{
if (options.ExistingConnection != null)
{
MyDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
}
else
{
MyDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
}
});
}
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(MyEntityFrameworkCoreModule).GetAssembly());
}
public override void PostInitialize()
{
// THIS IS WHERE I DO MIGRATIONS
EnsureMigrated();
if (!SkipDbSeed)
{
SeedHelper.SeedHostDb(IocManager);
}
}
private void EnsureMigrated()
{
// THIS IS HOW SeedHelper DOES IT
using (var uowManager = IocManager.ResolveAsDisposable<IUnitOfWorkManager>())
{
using (var uow = uowManager.Object.Begin(TransactionScopeOption.Suppress))
{
var context = uowManager.Object.Current.GetDbContext<MyDbContext>(MultiTenancySides.Host);
context.Database.Migrate();
uow.Complete();
}
}
}
However, this code throws an exception: connection is already in a transaction and cannot participate in another transaction
Any help appreciated.
4 Answer(s)
-
0
@devkev2403 can you try it with MultiTenantMigrateExecuter which is included in Migrator project. <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero-core/blob/dev/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Migrator/MultiTenantMigrateExecuter.cs">https://github.com/aspnetzero/aspnet-ze ... xecuter.cs</a>
-
0
Hi, thanks for the reply.
The migrator tool works and that is what we currently use. However, we want the migrations to be automatically applied on our staging system so we can have Continuous Delivery. We explicitly create the migrations but want them automatically applied.
We will be using the migrator tool on our live environment BTW! :)
-
0
Actually, this worked! Thanks
public class MultiTenantMigrateExecuter : ITransientDependency { public ILogger Log { get; } private readonly AbpZeroDbMigrator _migrator; private readonly IRepository<Tenant> _tenantRepository; private readonly IDbPerTenantConnectionStringResolver _connectionStringResolver; public MultiTenantMigrateExecuter( AbpZeroDbMigrator migrator, IRepository<Tenant> tenantRepository, ILogger log, IDbPerTenantConnectionStringResolver connectionStringResolver) { Log = log; _migrator = migrator; _tenantRepository = tenantRepository; _connectionStringResolver = connectionStringResolver; } public void Run() { var hostConnStr = _connectionStringResolver.GetNameOrConnectionString(new ConnectionStringResolveArgs(MultiTenancySides.Host)); if (hostConnStr.IsNullOrWhiteSpace()) { Log.Error("Configuration file should contain a connection string named 'Default'"); return; } Log.Info("Host database: " + ConnectionStringHelper.GetConnectionString(hostConnStr)); Log.Info("HOST database migration started..."); try { _migrator.CreateOrMigrateForHost(SeedHelper.SeedHostDb); } catch (Exception ex) { Log.Error("Canceled migrations - An error occured during migration of host database.", ex); return; } Log.Info("HOST database migration completed."); var migratedDatabases = new HashSet<string>(); var tenants = _tenantRepository.GetAllList(t => t.ConnectionString != null && t.ConnectionString != ""); for (var i = 0; i < tenants.Count; i++) { var tenant = tenants[i]; Log.Info($"Tenant database migration started... ({(i + 1)} / {tenants.Count})"); Log.Info("Name : " + tenant.Name); Log.Info("TenancyName : " + tenant.TenancyName); Log.Info("Tenant Id : " + tenant.Id); Log.Info("Connection string : " + SimpleStringCipher.Instance.Decrypt(tenant.ConnectionString)); if (!migratedDatabases.Contains(tenant.ConnectionString)) { try { _migrator.CreateOrMigrateForTenant(tenant); } catch (Exception ex) { Log.Error("An error occured during migration of tenant database. Skipped this tenant and will continue for others...", ex); } migratedDatabases.Add(tenant.ConnectionString); } else { Log.Info("This database has already migrated before (you have more than one tenant in same database). Skipping it...."); } Log.Info($"Tenant database migration completed. ({i + 1} / {tenants.Count})"); } Log.Info("All databases have been migrated."); } }
public class MyEntityFrameworkCoreModule : AbpModule { ... ... ... public override void PostInitialize() { EnsureMigrated(); if (!SkipDbSeed) { SeedHelper.SeedHostDb(IocManager); } } private void EnsureMigrated() { using (var migrateExecuter = IocManager.ResolveAsDisposable<MultiTenantMigrateExecuter>()) { migrateExecuter.Object.Run(); } } }
-
0
@devkev2403 great :)