如何在控制台应用程序中为 ConnectionString 定义 DataDirectory 以使用 EntityFramework Code First Migrations [英] How to define DataDirectory for ConnectionString in console application to work with EntityFramework Code First Migrations

查看:26
本文介绍了如何在控制台应用程序中为 ConnectionString 定义 DataDirectory 以使用 EntityFramework Code First Migrations的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I try to set location MyProject\App_Data\Cos.mdf for the database in App.config:

 <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Cos.mdf;Initial Catalog=Cos;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

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();
 }

显示的路径是(我把它贴出来说明我没有弄错):

The displayed path is(I paste it to show that I didn't make a mistake):

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

but then when I type in Package Manager Console enable-migrations change AutomaticMigrations to true, then type update-database I get error:

无法附加文件C:\Users\s8359_000\Documents\Visual Studio 2013\Projects\Projekt5 — kopia\Projekt5\bin\Debug\Cos.mdf"作为数据库Cos".

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

Why does .NET tries to create my database in Debug directory?! I went through 15 subjects on StackOverflow on this topic and it looks like everybody just duplicates the answers which don't work.

在回答 SRUTZKY 后编辑是的,你是对的,有错误.在您的回答之后,我尝试了更多组合,但不幸的是都没有.

EDIT AFTER ANSWER OF SRUTZKY Yes you are right there is error. I tried few more combination after your answer, unfortunately none worked.

  <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\baza.mdf;Initial Catalog=baza;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

和主要

  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我得到:

and after deleting Migrations directory and enable-migrations, automatic migrations to true, update-database I get:

PM> update-database 指定'-Verbose'标志查看SQL应用于目标数据库的语句.System.Data.SqlClient.SqlException (0x80131904):文件激活错误发生.物理文件名\baza.mdf"可能不正确.诊断并更正其他错误,然后重试该操作.创建数据库失败.无法创建列出的某些文件名.检查相关错误.在System.Data.SqlClient.SqlConnection.OnError(SqlException 异常,Boolean breakConnection, Action1 wrapCloseInAction) 在System.Data.SqlClient.SqlInternalConnection.OnError(SqlException异常,布尔 breakConnection,Action1 wrapCloseInAction) 在System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObjectstateObj, Boolean callerHasConnectionLock, Boolean asyncClose) atSystem.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler、SqlDataReader 数据流、BulkCopySimpleResultSet bulkCopyHandler、TdsParserStateObjectstateObj、Boolean&数据就绪)在System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(StringmethodName, Boolean async, Int32 timeout, Boolean asyncWrite) atSystem.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1完成,字符串方法名称,布尔值 sendToPipe,Int32 超时,布尔 asyncWrite) 在System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 在System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.b__0(DbCommandt, DbCommandInterceptionContext1 c) 在System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget目标,Func3 操作,TInterceptionContext 拦截上下文,Action3 执行,Action3 执行)在System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand命令,DbCommandInterceptionContext 拦截上下文)在System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass1a.b__19(DbConnection连接)在System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass33.b__32()在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.b__0()在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func1操作)在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action操作)在System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnectionsqlConnection, Action1 act) atSystem.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnectionsqlConnection, Action1 act) atSystem.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(Nullable1命令超时,DbConnection sqlConnection,字符串createDatabaseScript) 在System.Data.Entity.SqlServer.SqlProviderServices.DbCreateDatabase(DbConnection连接,Nullable1 commandTimeout,StoreItemCollectionstoreItemCollection) 在System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase(DbConnection连接,可空1 commandTimeout,StoreItemCollectionstoreItemCollection) 在System.Data.Entity.Core.Objects.ObjectContext.CreateDatabase() 在System.Data.Entity.Migrations.Utilities.DatabaseCreator.Create(DbConnection连接)在System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(ActionmustSucceedToKeepDatabase) 在System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(ActionmustSucceedToKeepDatabase) 在System.Data.Entity.Migrations.DbMigrator.Update(字符串目标迁移)在System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(字符串目标迁移)在System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()在 System.AppDomain.DoCallBack(CrossAppDomainDelegatecallBackDelegate) 在System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
在 System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner跑步者)在System.Data.Entity.Migrations.Design.ToolingFacade.Update(字符串targetMigration,布尔力)在System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()在System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action命令) ClientConnectionId:23ca49c1-4797-4bc3-8f16-f34fd77f2cbe A发生文件激活错误.物理文件名 '\baza.mdf' 可能不正确.诊断并纠正其他错误,然后重试手术.创建数据库失败.列出的某些文件名不能创建.检查相关错误.下午>

PM> update-database Specify the '-Verbose' flag to view the SQL statements being applied to the target database. System.Data.SqlClient.SqlException (0x80131904): A file activation error occurred. The physical file name '\baza.mdf' may be incorrect. Diagnose and correct additional errors, and retry the operation. CREATE DATABASE failed. Some file names listed could not be created. Check related errors. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext1 c) at System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func3 operation, TInterceptionContext interceptionContext, Action3 executing, Action3 executed) at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext) at System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass1a.b__19(DbConnection conn) at System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass33.b__32() at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.b__0() at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func1 operation) at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation) at System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection, Action1 act) at System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection sqlConnection, Action1 act) at System.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(Nullable1 commandTimeout, DbConnection sqlConnection, String createDatabaseScript) at System.Data.Entity.SqlServer.SqlProviderServices.DbCreateDatabase(DbConnection connection, Nullable1 commandTimeout, StoreItemCollection storeItemCollection) at System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase(DbConnection connection, Nullable1 commandTimeout, StoreItemCollection storeItemCollection) at System.Data.Entity.Core.Objects.ObjectContext.CreateDatabase() at System.Data.Entity.Migrations.Utilities.DatabaseCreator.Create(DbConnection connection) at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase) at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase) at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration) at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration) at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run() at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate) at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner) at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force) at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0() at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command) ClientConnectionId:23ca49c1-4797-4bc3-8f16-f34fd77f2cbe A file activation error occurred. The physical file name '\baza.mdf' may be incorrect. Diagnose and correct additional errors, and retry the operation. CREATE DATABASE failed. Some file names listed could not be created. Check related errors. PM>

推荐答案

问题 1 (of 2)

当您设置DataDirectory 的值时,它需要是一个目录,而不是一个文件.您正在传递 absolute 变量的值,即:

Problem 1 (of 2)

When you set the value of DataDirectory, it needs to be a directory, not a file. You are passing in the value of the absolute variable which is:

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

并且其中包含文件名.那是无效的.DataDirectory 是一个替代值,因此指定:

and which contains the filename. That is not valid. DataDirectory is a substitution value, so specifying:

AttachDbFilename=|DataDirectory|\Cos.mdf

在连接字符串中会翻译成:

in the connection string would translate into:

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

那不是有效的路径.所以看起来 .NET 看到 DataDirectory 的值无效并且不使用它,因此在当前工作目录中启动.

That is not a valid path. So it appears that .NET sees that the value of DataDirectory is not valid and does not use it and hence starts in the current working directory.

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

Use Path.GetDirectoryName(relative) instead of Path.GetFullPath(relative) to set the value of absolute and it should work as it will set the value of DataDirectory to be:

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

连接字符串的 MSDN 页面有一些关于底部,在标题为支持 |DataDirectory| 替换字符串..."的部分中.

The MSDN page for Connection Strings has some additional details towards the bottom, in the section titled, "Support for the |DataDirectory| Substitution String..."

  1. DataDirectory"在 AppDomain 中设置.
  2. 控制台应用有自己的 AppDomain,它们在启动时创建,退出时消失.
  3. 包管理器(您运行 Update-Database 的位置)无权访问您正在设置DataDirectory"值的控制台应用的 AppDomain.
  4. 您需要:
  1. "DataDirectory" is set in the AppDomain.
  2. Console Apps have their own AppDomains that are created when they start and go away when they exit.
  3. Package Manager (where you are running Update-Database) does not have access to the AppDomain of your console app where you are setting the value of "DataDirectory".
  4. You need to either:
  1. 在包管理器中以编程方式设置DataDirectory",或
  2. 在控制台应用的上下文中以编程方式运行update-database"

我不知道如何以编程方式与包管理器进行交互,但我确实设法弄清楚了如何以编程方式触发更新数据库"进程.只需在设置DataDirectory"的值后添加以下行:

I don't know how to programatically interact with Package Manager, but I did manage to figure out how to programatically fire the "update-database" process. Just add the following line just after you set the value of "DataDirectory":

Database.SetInitializer(new
    MigrateDatabaseToLatestVersion<YourDataContextName, Configuration>()
 );

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

You will also need at least one, if not two, using statements:

  • 使用 System.Data.Entity;
  • 使用 ProjectName.Migrations;//Migrations\Configuration.cs 的命名空间

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

Please note that this alone does not create the database. Any pending changes will be published when you first access the database via the 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<Projekt5Context, Configuration>()
 );
// database not created yet

using (var db = new Projekt5Context())
{
  db.Things.Add(new Thing { Name = "OMG This works!" });
  db.SaveChanges();
} 
// database CREATED!

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

Also, you might need to call the following, one time, via Package Manager (it doesn't do anything immediately to the database so the connection string is not accessed):

Add-Migration InitialMigration

有关详细信息,请参阅 代码优先迁移.

For more info, please see the MSDN page for Code First Migrations.

一旦调用 SetInitializer 的这行代码与 MigrateDatabaseToLatestVersion 一起存在,它就会这样做:每次运行时(这就是为什么在开始时这样做的原因)控制台应用程序)它同步模型"(现在编译到程序集)和数据库中的内容之间的任何更改,确保数据库具有最新版本.这假设任何新表都在 DbContext 类中表示.但是不需要运行额外的包管理器命令.

Once this line of code to call SetInitializer is there with MigrateDatabaseToLatestVersion, it does just that: each time it runs (which is why this is done at the beginning of the console app) it syncs any changes between what is in the "model" (that is now compiled into the Assembly) and the database, making sure that the database has the latest version. This assumes that any new tables are represented in the DbContext class. But no additional Package Manager commands need to be ran.

这篇关于如何在控制台应用程序中为 ConnectionString 定义 DataDirectory 以使用 EntityFramework Code First Migrations的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆