Param(
[ValidateNotNullOrEmpty()][string]$assemblyFile,
[ValidateNotNullOrEmpty()][string]$connectionString
# [ValidateNotNullOrEmpty()][string]$server,
# [ValidateNotNullOrEmpty()][string]$databaseName,
# [ValidateNotNullOrEmpty()][string]$userName,
# [ValidateNotNullOrEmpty()][string]$password
)
$assemblyFolder = [System.IO.Path]::GetDirectoryName($assemblyFile)
$OnAssemblyResolve = [System.ResolveEventHandler] {
param($sender, $e)
# First load the assemblies already in our app domain
foreach($a in [System.AppDomain]::CurrentDomain.GetAssemblies())
{
if ($a.FullName -eq $e.Name)
{
return $a
}
}
$fn = Join-Path $assemblyFolder "$($e.Name.Split(',')[0]).dll"
if (Test-Path $fn)
{
$ass = [Reflection.Assembly]::LoadFile($fn)
return $ass
}
return $null
}
[System.AppDomain]::CurrentDomain.add_AssemblyResolve($OnAssemblyResolve)
Set-Location ($assemblyFolder)
[System.Reflection.Assembly] $assembly = [System.Reflection.Assembly]::LoadFile($assemblyFile)
$types = $null
try
{
$types = $assembly.GetTypes()
}
catch [Exception]
{
$ErrorMessage = $_.Exception.Message
throw "Failed to load types from assembly"
}
$configurationType = [System.Type]::GetType("System.Data.Entity.Migrations.DbMigrationsConfiguration, EntityFramework")
$migratorType = [System.Type]::GetType("System.Data.Entity.Migrations.DbMigrator, EntityFramework")
$connectionInfoType = [System.Type]::GetType("System.Data.Entity.Infrastructure.DbConnectionInfo, EntityFramework")
if ($configurationType -eq $null -or $migratorType -eq $null -or $connectionInfoType -eq $null)
{
throw "Failed to load entity framework"
}
$migrationConfigurationTypes = @($types | ? { $configurationType.IsAssignableFrom($_) })
if ($migrationConfigurationTypes.Length -ne 1)
{
throw "Failed to find single migration type for Entity framework in the assembly to migrate, found $($migrationConfigurationTypes.Length) migration configuration types"
}
Write-Warning "If you see an error similar to 'Could not find a connection string named [connection string name] in the application config', try changing your DbContext descendent to use the DbContext('connection string name') constructor syntax instead of DbContext('name=connection string name'). This is a known bug in EntityFramework."
#$builder = New-Object System.Data.SqlClient.SqlConnectionStringBuilder
# Need to use psbase, otherwise these properties throw an exception
#$builder.psbase.DataSource = $server
#$builder.psbase.InitialCatalog = $databaseName
#$builder.psbase.UserID = $userName
#$builder.psbase.Password = $password
#$connectionString = $builder.ToString()
$configuration = [System.Activator]::CreateInstance($migrationConfigurationTypes[0])
$connectionInfo = New-Object $connectionInfoType ($connectionString, "System.Data.SqlClient")
$configuration.TargetDatabase = $connectionInfo
$migrator = [System.Activator]::CreateInstance($migratorType, @($configuration))
$migrator.Update()
Write-Host 'Successfully migrated database'
Tuesday, June 21, 2016
PowerShell script to execute an Entity Framework Migration
I got sick and tired of coming up with hacks for including Entity Framework migrations as part of my deployment processes, so I came up with a much cleaner hack in the form of a PowerShell script that can be used to execute a database migration given an assembly and a connection string. This script does have one caveat though: for some reason if it's run more than once in a given PowerShell session, it causes a stack overflow exception, and I haven't been able to figure out why. I guess I'll have to leave it as an exercise to you. Have at it:
No comments:
Post a Comment