Reputation: 1329
I am creating a migration bundle for external usage by our database team to execute Entity Framework Migrations. The bundle is composed of an Entity Framework Project (which includes all our migrations) and the ef6.dll
migration tool from the Entity Framework 6.4 NuGet package, which is located at ef64package/tools/netcoreapp3.0/any
.
The migration bundle also contains a simple PowerShell script that executes ef6.dll
somehow like this:
dotnet .\ef6.dll database update --verbose --assembly MyApp.Core.EF.dll --connection-string "Data Source=localhost;Initial Catalog=MyApp;Trusted_Connection=True;" --connection-provider "System.Data.SqlClient"
Using the migrate.exe
(in previous versions of Entity Framework) and ef6.exe
for .NET Framework this bundle worked just fine. But after switching to .NET Core and ef6.dll
the execution results in the following error:
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Entity.Internal.LazyInternalConnection.CreateConnectionFromProviderName(String providerInvariantName)
at System.Data.Entity.Internal.LazyInternalConnection.InitializeFromConnectionStringSetting(ConnectionStringSettings appConfigConnection)
at System.Data.Entity.Internal.LazyInternalConnection.Initialize()
at System.Data.Entity.Internal.LazyInternalConnection.get_Connection()
at System.Data.Entity.Internal.LazyInternalContext.get_Connection()
at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo, Func`1 resolver)
at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbConnectionInfo connectionInfo)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, Boolean calledByCreateDatabase)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Infrastructure.Design.Executor.CreateMigrator(DbMigrationsConfiguration configuration)
at System.Data.Entity.Infrastructure.Design.Executor.UpdateInternal(String targetMigration, Boolean force, DbConnectionInfo connectionInfo, String migrationsConfigurationName)
at System.Data.Entity.Infrastructure.Design.Executor.Update.<>c__DisplayClass0_0.<.ctor>b__0()
at System.Data.Entity.Infrastructure.Design.Executor.OperationBase.Execute(Action action)
Object reference not set to an instance of an object.
A very generic error, but according to the EF source code (https://github.com/dotnet/ef6/blob/02104044fae2aca5d3a1f50f55f4af940a3c64a8/src/EntityFramework/Internal/LazyInternalConnection.cs), i looks like a DbProviderFactory
registration is missing or the providerInvariantName
is messed up in the process. I've got a feeling this is a side effect due to a missing configuration or dependency. But so far i could not figure out how to fix this error.
Any ideas on how to fix this error? Also other approaches in creating a standalone migration bundle are highly welcome.
Thanks in advance!
Upvotes: 4
Views: 1727
Reputation: 31
Migrations for Entity Framework (6.4.4) + Net Core 3.x require an executable application as an entry point. (The 'old' migrations were fine with just the dll containing database context.)
You just need to add an executable application (or create a dummy commandline app), and specify it in the command.
This is non-obvious, because all examples assume you have only single project with single dll, and do not warn about this.
If you check the syntax of ef6.dll, you will see that parameter for main application dll... is not present.
But, it can be worked around by using the undocumented dotnet exec
syntax.
dotnet exec --depsfile Your.App.Project.deps.json --runtimeconfig Your.App.Project.runtimeconfig.json .\ef6.dll" database update --verbose --assembly Your.Database.Project.dll --connection-string "<standard sql string>"
Please note that .deps file and .runtimeconfig come from your executable application, and that all .dll files for said application must be present in the folder (tool will check that). The remaining parameters are standard for ef6.dll - name of .dll file containing database context, connection string, optionally provider type.
Some caveats:
Microsoft.Data.SqlClient.dll
needs some secret child dll in runtimes folder.Server=.\\SQLEXPRESS
instead of Server=.\SQLEXPRESS
Author of this post officially hates the ef6.dll now.
Upvotes: 3
Reputation: 18556
This is how I got it to work:
dotnet exec --depsfile MyApp.Core.EF.json --runtimeconfig MyApp.Core.EF.runtimeconfig.json "....\packages\entityframework\6.4.0\tools\netcoreapp3.0\any\ef6.dll" database update --assembly MyApp.Core.EF.dll --connection-string "xxx" --verbose
See also this Github issue or Entity Framework Migration Azure DevOps Release Pipeline.
Upvotes: 2