如何在控制台应用程序中定义为DataDirectory目录使用的ConnectionString代码的EntityFramework迁移第一工作 [英] How to define DataDirectory for ConnectionString in console application to work with EntityFramework Code First Migrations

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

问题描述

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

 <&是connectionStrings GT; 
<添加名称=DefaultConnection的connectionString =数据源=(的LocalDB)\v11.0; AttachDbFilename = | DataDirectory目录| \Cos.mdf;初始目录=产地来源证;集成安全性= TRUE; MultipleActiveResultSets =真的providerName =System.Data.SqlClient的/>
< /&是connectionStrings GT;

的Program.cs 我写的:

 静态无效的主要(字串[] args){

串亲戚= @.. \ ..\App_Data\Cos.mdf;
串绝对= Path.GetFullPath(相对);

AppDomain.CurrentDomain.SetData(DataDirectory目录,绝对);
Console.WriteLine(绝对);
Console.ReadKey();
}

显示的路径是(我贴吧表明,我没有做错误):





但后来当我在软件包管理控制台中输入启用的迁移变更 AutomaticMigrations 为true,然后键入更新数据库我得到错误:



无法附加文件C:\Users\s8359_000\Documents\Visual工作室2013\Projects\Projekt5 - kopia\Projekt5\bin\Debug\Cos.mdf'数据库'因为'。



为什么.NET试图在调试目录下创建我的数据库?我通过15名受试者继续计算器关于这一主题,它看起来像所有人都在重复这不工作的答案。



编辑答案SRUTZKY <后/ STRONG>
是的,你说得对存在误差。我试过你的答案后,几个组合,遗憾的是没有工作。



 <&是connectionStrings GT; 
<添加名称=DefaultConnection的connectionString =数据源=(的LocalDB)\v11.0; AttachDbFilename = | DataDirectory目录| \baza.mdf;初始目录=巴扎;集成安全性= TRUE; MultipleActiveResultSets =真的providerName =System.Data.SqlClient的/>
< /&是connectionStrings GT;

和主

 静态无效的主要(字串[] args){

Console.WriteLine(BEFORE:+ AppDomain.CurrentDomain.GetData(DataDirectory目录));
串亲戚= @.. \..\App_Data\Cos.mdf
串绝对= Path.GetFullPath(相对);
绝对= Path.GetDirectoryName(@absolute);
AppDomain.CurrentDomain.SetData(DataDirectory目录,@absolute);
Console.WriteLine(@absolute);
Console.WriteLine(AppDomain.CurrentDomain.GetData(DataDirectory目录));
Console.ReadKey();
}



然后我得到控制台:





和删除后,迁移目录,启用的迁移,自动迁移到真正的,更新数据库我得到:




PM>更新数据库指定-Verbose'标志来查看SQL $ b被施加到目标数据库$ b语句。
System.Data.SqlClient.SqlException(0x80131904):发生文件激活
错误。物理文件名'\baza.mdf'可能不正确。
诊断并更正其他错误,然后重试操作。
CREATE DATABASE失败。列出的某些文件名不能创建。
检查相关的错误。在
System.Data.SqlClient.SqlConnection.OnError(SqlException异常,
布尔breakConnection,行动 1 wrapCloseInAction)在
System.Data.SqlClient.SqlInternalConnection.OnError( SQLEXCEPTION
例外,布尔breakConnection,动作
1 wrapCloseInAction)在
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
stateObj,布尔callerHasConnectionLock,布尔asyncClose)在
System.Data.SqlClient.TdsParser.TryRun(runBehavior runBehavior,
的SqlCommand cmdHandler,SqlDataReader的数据流,
BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject
stateObj,布尔和放大器; dataReady)在
System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(字符串
方法名,布尔异步,的Int32超时,布尔asyncWrite)在
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource 1
完成,字符串methodName中,布尔sendToPipe,超时的Int32,
布尔asyncWrite)留在
System.Data.Entity.Infrastructure
System.Data.SqlClient.SqlCommand.ExecuteNonQuery()。 Interception.DbCommandDispatcher< NonQuery> b__0(的DbCommand
T,DbCommandInterceptionContext
1 c)在
System.Data.Entity.Infrastructure.Interception.InternalDispatcher 1 .Dispatch [TTarget,TInterceptionContext,TResult](TTarget
目标,Func键
3次手术,TInterceptionContext interceptionContext,
行动 3执行,操作 System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(的DbCommand
命令,DbCommandInterceptionContext interceptionContext)在
$ System.Data.Entity.SqlServer.SqlProviderServices C> 3执行)。 <> 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](Func键 1

操作)在
System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(动作
操作)在
System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(的DbConnection
的SqlConnection,操作
1在
System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(的DbConnection
的SqlConnection,动作 1的行为)在
法案) System.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(可空
1
的CommandTimeout,SqlConnection的的DbConnection,字符串
createDatabaseScript)在
System.Data.Entity.SqlServer。 SqlProviderServices.DbCreateDatabase(的DbConnection
连接,可为空 1的CommandTimeout,StoreItemCollection
storeItemCollection)(在
System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase的DbConnection
连接,可为空
1的CommandTimeout在
System.Data这,storeItemCollection
storeItemCollection)在
System.Data.Entity.Core.Objects.ObjectContext.CreateDatabase() .Entity.Migrations.Utilities.DatabaseCreator.Create(的DbConnection
连接)在
System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(动作
mustSucceedToKeepDatabase)在
System.Data这.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(动作
mustSucceedToKeepDatabase)在
System.Data.Entity.Migrations.DbMigrator.Update(字符串
targetMigration)在
System.Data这.Entity.Migrations.Infrastructure.MigratorBase.Update(字符串
targetMigration)在
System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
在System.AppDomain.DoCallBack (CrossAppDomainDelegate
callBackDelegate)在
System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)结果
在System.Data.Entity.Migrations.Design.ToolingFacade.Run(跑垒员
亚军)在在
System.Data.Entity.Migrations.UpdateDatabaseCommand
System.Data.Entity.Migrations.Design.ToolingFacade.Update(字符串
targetMigration,布尔力)LT;> c__DisplayClass2。 < .ctor> b__0()在
System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(动作
命令)
ClientConnectionId:23ca49c1-4797-4bc3-8f16-f34fd77f2cbe一个$ b发生$ b档激活错误。物理文件名'\baza.mdf'可以
是不正确的。诊断和纠正其他错误,然后重试
操作。 CREATE DATABASE失败。列出的某些文件名不能创建
。检查相关的错误。 PM>



解决方案

问题1(2)



当您设置 DataDirectory目录的价值,它必须是一个目录,而不是文件。您传入绝对变量的值,它是:



  C:\Users\s8359_000\Documents\Visual工作室2013\Projects\Projekt5  -  kopia\Projekt5\App_Data\Cos.mdf 

和其中包含的文件名。这是无效的。 DataDirectory目录是一个替代值,因此指定:

  AttachDbFilename = | DataDirectory目录| \Cos.mdf 

在连接字符串中会转化为:

$ b $ kopia\Projekt5\App_Data\Cos - \Users\s8359_000\Documents\Visual工作室2013\Projects\Projekt5:乙

 ç .mdf\Cos.mdf 

这不是一个有效的路径。所以看来.NET看到了的 DataDirectory目录的值是无效的,并且不使用它,因此在当前工作目录开始。



使用 Path.GetDirectoryName(相对)而不是 Path.GetFullPath(相对)设置值绝对,它应该工作,因为它会设定 DataDirectory目录是的值:

  C:\Users\s8359_000\Documents\Visual工作室2013\Projects\Projekt5  -  kopia\Projekt5\App_Data 

有关的连接字符串有朝下方一些额外的细节,在标题为,为支持| DataDirectory |替换字符串......



问题2




  1. DataDirectory目录设置在AppDomain中。
  2. 控制台应用程序有当他们开始了创建自己的应用程序域和离开时,他们退出。

  3. 软件包管理器(你在哪里运行更新 - 数据库)不具有访问您的控制台应用程序,你在哪里设置DataDirectory目录的价值在AppDomain

  4. 您需要或者:

    1. 编程设置DataDirectory目录,在包管理器,或

    2. 编程您的控制台应用程序的环境中运行更新数据库




我不知道如何以编程方式与程序包管理器进行交互,但我没有设法弄清楚如何编程火更新数据库的过程。只需添加以下行刚过设置DataDirectory目录的值:



<预类=郎-CS prettyprint-覆盖> Database.SetInitializer (新
MigrateDatabaseToLatestVersion< YourDataContextName,结构>()
);

您还需要至少一个,如果不是两个,使用语句:




  • 使用System.Data.Entity的;

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



请注意,这本身并不能创建数据库。 。任何挂起的更改将公布当你第一次的访问的通过的DbContext数据库



例如:



<预类=郎-CS prettyprint-覆盖> 使用System.Data.Entity的;使用Projekt5.Migrations
;

....

串亲戚= @.. \..\App_Data\Cos.mdf
串的绝对= Path.GetDirectoryName(绝对);
AppDomain.CurrentDomain.SetData(DataDirectory目录,绝对);
Database.SetInitializer(新
MigrateDatabaseToLatestVersion< Projekt5Context,结构>()
);
//数据库尚未使用(VAR DB =新Projekt5Context())
{
db.Things.Add(新的东西{名称尚未

=OMG这工作})!;
db.SaveChanges();
}
//数据库中创建的!



另外,你的 的可能需要调用下面,一时间,通过软件包管理器(所以在连接字符串不访问它不会立即做任何数据库):



<预类=郎无prettyprint-覆盖> 添加迁移InitialMigration

有关更多信息,请参阅MSDN页的代码首先迁移



一旦这行代码来调用 SetInitializer 是否有与 MigrateDatabaseToLatestVersion ,它只是做:它每次运行时(这所以这是在控制台应用程序的开始时进行),这之间的同步是什么在模式()和数据库的任何更改被编译进了大会,确保数据库具有最新版本。这假定任何新表在的DbContext 类表示。但没有额外的软件包管理器的命令必须跑。


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>

In Program.cs I wrote:

 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):

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

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

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.

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>

and the Main

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

then I get in console:

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

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>

解决方案

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

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

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.

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

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

Problem 2 (of 2)

  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. programatically set "DataDirectory" in Package Manager, or
    2. programatically run "update-database" within the context of your console app

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

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

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

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.

Example:

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.

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.

这篇关于如何在控制台应用程序中定义为DataDirectory目录使用的ConnectionString代码的EntityFramework迁移第一工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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