如何在控制台应用程序中为ConnectionString定义DataDirectory以使用EntityFramework Code First Migrations

我尝试在App.config为数据库设置位置MyProject\App_Data\Cos.mdf

     

Program.cs我写道:

  static void Main(string[] args) { string relative = @"..\..\App_Data\Cos.mdf"; string absolute = Path.GetFullPath(relative); AppDomain.CurrentDomain.SetData("DataDirectory", absolute); Console.WriteLine(absolute); Console.ReadKey(); } 

显示的路径是(我粘贴它表明我没有犯错):

在此处输入图像描述

但是当我输入包管理器控制台enable-migrationsAutomaticMigrations更改为true,然后键入update-database我收到错误:

Cannot attach the file 'C:\Users\s8359_000\Documents\Visual Studio 2013\Projects\Projekt5 — kopia\Projekt5\bin\Debug\Cos.mdf' as database 'Cos'.

为什么.NET尝试在Debug目录中创建我的数据库?! 我在StackOverflow上讨论了这个主题的15个主题,看起来每个人都只是重复了不起作用的答案。

在SRUTZKY回答后编辑是的,你是对的,有错误。 你回答后我尝试了更多的组合,不幸的是没有一个工作。

     

和主要的

  static void Main(string[] args) { Console.WriteLine("BEFORE:" + AppDomain.CurrentDomain.GetData("DataDirectory")); string relative = @"..\..\App_Data\Cos.mdf"; string absolute = Path.GetFullPath(relative); absolute = Path.GetDirectoryName(@absolute); AppDomain.CurrentDomain.SetData("DataDirectory", @absolute); Console.WriteLine(@absolute); Console.WriteLine(AppDomain.CurrentDomain.GetData("DataDirectory")); Console.ReadKey(); } 

然后我进入控制台:

在此处输入图像描述

删除Migrations目录和enable-migrations ,自动迁移到true, update-database我得到:

PM> update-database指定’-Verbose’标志以查看应用于目标数据库的SQL语句。 System.Data.SqlClient.SqlException(0x80131904):发生文件激活错误。 物理文件名’\ baza.mdf’可能不正确。 诊断并更正其他错误,然后重试该操作。 CREATE DATABASE失败。 无法创建列出的某些文件名。 检查相关错误。 System.Data.SqlClient.TdsParser上System.Data.SqlClient.SqlInternalConnection.OnError(SqlExceptionexception,Boolean breakConnection,Action 1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction) System.Data.SqlClient.SqlCommand的System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,Boolean&dataReady)中的.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean callerHasConnectionLock,Boolean asyncClose)。 System.Data.SqlClient.SqlCommand的System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource 1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.b__0(DbCommand t, DbCommandInterceptionContext RunExecuteNonQueryTds(String methodName,Boolean async,Int32 timeout,Boolean asyncWrite) 1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.b__0(DbCommand t, DbCommandInterceptionContext 1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.b__0(DbCommand t, DbCommandInterceptionContext 1 c) 1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func 3操作,TInterceptionContext interceptionContext,Action 3 executing, Action 3)在System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand命令,DbCommandInterceptionContext interceptionContext)的System.Data.Entity.SqlServer.SqlProviderServices。 c__DisplayClass1a.b__19(DbConnection conn)at System System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute [TResult]上的System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy。 c__DisplayClass1.b__0()处于.Data.Entity.SqlServer.SqlProviderServices。 c__DisplayClass33.b__32() 1 operation) at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation) at System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection, Action Func 1 operation) at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation) at System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection, Action 在System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection sqlConnection,Action 1 act) at System.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(Nullable 1 commandTimeout,DbConnection sqlConnection,String createDatabaseScript)at onction,Action 1 act) at System.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(Nullable System.Data.Entity.SqlServer.SqlProviderServices.DbCreateDatabase(DbConnection连接,Nullable 1 commandTimeout, StoreItemCollection storeItemCollection) at System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase(DbConnection connection, Nullable 1 commandTimeout,StoreItemCollection storeItemCollection)。系统中的System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)上的System.Data.Entity.Migrations.Utilities.DatabaseCreator.Create(DbConnection连接)中的Data.Entity.Core.Objects.ObjectContext.CreateDatabase()。 Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)at at 位于System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run的System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)中的System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)( )在System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)的System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
在System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)的System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)中,System.Data.Entity.Migrations.UpdateDatabaseCommand上的System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration,Boolean force)。 c__DisplayClass2。 b__0()在System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(操作命令)ClientConnectionId:23ca49c1-4797-4bc3-8f16-f34fd77f2cbe发生文件激活错误。 物理文件名’\ baza.mdf’可能不正确。 诊断并更正其他错误,然后重试该操作。 CREATE DATABASE失败。 无法创建列出的某些文件名。 检查相关错误。 PM>

问题1(共2个)

设置DataDirectory的值时,它需要是目录,而不是文件。 您传递的absolute变量的值是:

 C:\Users\s8359_000\Documents\Visual Studio 2013\Projects\Projekt5 — kopia\Projekt5\App_Data\Cos.mdf 

并包含文件名。 那是无效的。 DataDirectory是替换值,因此指定:

 AttachDbFilename=|DataDirectory|\Cos.mdf 

在连接字符串中将转换为:

 C:\Users\s8359_000\Documents\Visual Studio 2013\Projects\Projekt5 — kopia\Projekt5\App_Data\Cos.mdf\Cos.mdf 

那不是一条有效的道路。 因此看起来.NET看到DataDirectory的值无效且不使用它,因此从当前工作目录开始。

使用Path.GetDirectoryName(relative)而不是Path.GetFullPath(relative)来设置absolute ,它应该工作,因为它将DataDirectory的值设置为:

 C:\Users\s8359_000\Documents\Visual Studio 2013\Projects\Projekt5 — kopia\Projekt5\App_Data 

连接字符串的MSDN页面在标题为“支持| DataDirectory |替换字符串…”的部分中有一些额外的详细信息。

问题2(共2个)

  1. “DataDirectory”在AppDomain中设置。
  2. 控制台应用程序有自己的AppDomain,它们在启动时创建,在退出时消失。
  3. 程序包管理器(运行Update-Database )无法访问控制台应用程序的AppDomain,您可以在其中设置“DataDirectory”的值。
  4. 你需要:
    1. 以编程方式在程序包管理器中设置“DataDirectory”
    2. 以编程方式在控制台应用程序的上下文中运行“update-database”

我不知道如何以编程方式与Package Manager进行交互,但我确实设法弄清楚如何以编程方式触发“update-database”进程。 只需在设置“DataDirectory”的值后添加以下行:

 Database.SetInitializer(new MigrateDatabaseToLatestVersion() ); 

您还需要至少一个(如果不是两个) using语句:

  • using System.Data.Entity;
  • using ProjectName.Migrations; // namespace of Migrations\Configuration.cs

请注意,仅此一项不会创建数据库。 当您首次通过DbContext 访问数据库时,将发布任何挂起的更改。

例:

 using System.Data.Entity; using Projekt5.Migrations; .... string relative = @"..\..\App_Data\Cos.mdf"; string absolute = Path.GetDirectoryName(absolute); AppDomain.CurrentDomain.SetData("DataDirectory", absolute); Database.SetInitializer(new MigrateDatabaseToLatestVersion() ); // database not created yet using (var db = new Projekt5Context()) { db.Things.Add(new Thing { Name = "OMG This works!" }); db.SaveChanges(); } // database CREATED! 

此外,您可能需要通过程序包管理器调用以下命令(它不会立即对数据库执行任何操作,因此不会访问连接字符串):

 Add-Migration InitialMigration 

有关详细信息,请参阅CodeDN 迁移的MSDN页面。

一旦调用SetInitializer这行代码与SetInitializer一起MigrateDatabaseToLatestVersion ,它就MigrateDatabaseToLatestVersion :每次运行时(这就是为什么这在控制台应用程序的开头完成)它会同步“模型”中的内容之间的任何变化(现在已编译到程序集中)和数据库,确保数据库具有最新版本。 这假设任何新表都在DbContext类中表示。 但是不需要运行其他程序包管理器命令。

您可以在Enable-Migrations命令创建的Configuration类中为Update-Database设置DataDirectory:

 internal sealed class Configuration : DbMigrationsConfiguration { public Configuration() { AutomaticMigrationsEnabled = false; var dataDirPath = ""; AppDomain.CurrentDomain.SetData("DataDirectory", dataDirPath); } } 

要将DataDirectory指向控制台项目和EF代码首次迁移下名为“AppData”的文件夹,您必须执行以下操作:

 public static class AppData { public static void Set() { // Set the |DataDirectory| path used in connection strings to point to the correct directory for console app and migrations var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; string relative = @"..\..\App_Data\"; string absolute = Path.GetFullPath(Path.Combine(baseDirectory, relative)); AppDomain.CurrentDomain.SetData("DataDirectory", absolute); } } 

然后从控制台应用程序和数据库迁移的入口点调用AppData.Set()

1)控制台应用程序的Main-method或Startup-class:

 class Program { static void Main() { AppData.Set(); } } 

2)EF代码首次迁移

 public class DatabaseContext : DbContext { // Add this constructor to your database context public DatabaseContext() : base() { AppData.Set(); } // DbSet's are defined here }