EF 代码第一次迁移报错“对象已断开连接或在服务器上不存在”
Posted
技术标签:
【中文标题】EF 代码第一次迁移报错“对象已断开连接或在服务器上不存在”【英文标题】:EF code first migration error "Object has been disconnected or does not exist at the server" 【发布时间】:2015-06-23 13:32:54 【问题描述】:我在 SQL Server 2008 上使用 Entity Framework 6.1.1,并且我有一个长时间运行的代码首次迁移(大约 20 分钟)。它到达最后,然后给出以下错误。
System.Runtime.Remoting.RemotingException: Object '/f10901d8_94fe_4db4_bb9d_51cd19292b01/bq6vk4vkuz5tkri2x8nwhsln_106.rem' has been disconnected or does not exist at the server.
at System.Data.Entity.Migrations.Design.ToolingFacade.ToolLogger.Verbose(String sql)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbTransaction transaction, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbConnection connection)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClass30.<ExecuteStatements>b__2e()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements, DbTransaction existingTransaction)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, IEnumerable`1 systemOperations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
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)
迁移的重点是更新数据库中存储一些二进制数据的 MIME 类型的字段。它遍历每一行,读取二进制数据,尝试确定它是什么类型的内容,然后将适当的 MIME 类型值写入该行。
以下脚本使用 ADO.NET 生成要运行的更新语句列表。我使用 ADO.NET 是因为我必须使用 .NET 的图像库 (System.Drawing.Imaging.ImageFormat) 来确定每行中二进制内容的类型(它将是 jpeg、png 或 pdf)。
public override void Up()
List<string> updateStatements = new List<string>();
using(SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]))
SqlCommand cmd = new SqlCommand("SELECT Table1ID, Image FROM Table1"), conn);
conn.Open();
//read each record and update the content type value based on the type of data stored
using (SqlDataReader reader = cmd.ExecuteReader())
while (reader.Read())
long idValue = Convert.ToInt64(reader["Table1ID"]);
byte[] data = (byte[])reader["Image"];
string contentType = GetMimeType(data);
updateStatements.Add(string.Format("UPDATE Table1 SET Content_Type = 0 WHERE Table1ID = 1", contentType, idValue));
foreach (string updateStatement in updateStatements)
Sql(updateStatement);
public string GetMimeType(byte[] document)
if (document != null && document.Length > 0)
ImageFormat format = null;
try
MemoryStream ms = new MemoryStream(document);
Image img = Image.FromStream(ms);
format = img.RawFormat;
catch (Exception)
/* PDF documents will throw exceptions since they aren't images but you can check if it's really a PDF
* by inspecting the first four bytes with will be 0x25 0x50 0x44 0x46 ("%PDF"). */
if (document[0] == 0x25 && document[1] == 0x50 && document[2] == 0x44 && document[3] == 0x46)
return PDF;
else
return NULL;
if (format.Equals(ImageFormat.Jpeg))
return JPG;
else if (format.Equals(System.Drawing.Imaging.ImageFormat.Png))
return PNG;
return NULL;
我已经看到this five year old post 和它链接的文章似乎不再存在。至少我找不到他们。
有人知道这里发生了什么吗?
-- 更新-- 这似乎与迁移运行所需的时间有关。我创建了一个迁移,除了睡眠 22 分钟之外什么都不做
public override void Up()
System.Threading.Thread.Sleep(1320000);
我得到了同样的错误。所以这似乎是一个超时的事情。我不是 100% 他们所指的服务器上的对象,我在这个问题上找不到太多,因为它与代码优先迁移有关。
我尝试将迁移 Configuration.cs
文件中的 CommandTimeout
属性设置为 5000,但没有帮助。我还尝试将 SQL Server 的 Remove query timeout
设置为 0 以防止任何超时,但这也无济于事。
【问题讨论】:
是的,可能与超时有关。如果可能的话,我会尝试运行外部迁移。 ***.com/questions/18900204/… 我可以这样做,但这不是一个有吸引力的选项,因为这样我就不能只在任何数据库上运行迁移以使其保持最新状态。另外,我必须记住手动运行这个其他脚本。我的意思是,如果事情就是这样,那么我想我会这样做,但必须这样做似乎很不靠谱。 也许可以考虑将该代码移动到 Application Initializer Seed() 方法中。 if (!upToDate) 做更新 . 您有没有找到解决问题的方法?在具有数百万条记录的数据库上应用迁移时,我遇到了同样的问题... 这指向一个解决方案,我发现它有效 - ***.com/questions/18900204/… 【参考方案1】:从 [GitHub EntityFramework 6 第 96 期][https://github.com/aspnet/EntityFramework6/issues/96#issuecomment-289782427]] 挖取
问题在于 ToolLogger 租用生命周期(基类 MigrationsLogger 是 MarshalByRefObject) 是默认的 (5 分钟)。 ToolingFacade 创建记录器,它位于 主程序的应用程序域。迁移在不同的应用程序中运行 领域。如果迁移时间超过 5 分钟,则尝试记录 任何进一步的信息都会导致此错误。一个解决方案是 增加主程序中的租约寿命。所以……主要是 程序,在创建 ToolingFacade 之前,设置租约生命周期 更长的时间:
using System.Runtime.Remoting.Lifetime;
...
LifetimeServices.LeaseTime = TimeSpan.FromHours(1);
【讨论】:
一个小提示:把它放在你的迁移文件中,因为这适用于整个应用程序域。这将确保它仅在应用新迁移时使用。 “迁移”文件是什么意思。您是指单个迁移文件还是迁移配置文件?无论哪种情况,这都不能防止错误。 看起来这种解决方法在 6.3 中可能已被破坏 我们过去曾使用过这种解决方法,但它不再起作用了。在 EF 6.4 中它也不起作用。【参考方案2】:这是 Entity Framework 6 中的 known issue,用于需要很长时间才能完成的脚本。
解决方法是通过Update-Database
命令仅生成 SQL 脚本,并直接在 SQL Server 上执行生成的 SQL。为了只生成 SQL,您必须使用 -Script
标志:
Update-Database -Script
【讨论】:
如果它确实生成了有效的脚本,那将是一个很好的解决方法。根据我的经验,生成的脚本经常缺少 GO 语句,导致脚本在没有人工干预的情况下无法运行。【参考方案3】:这让我们很头疼。该问题似乎是由于 EF 迁移实用程序的设计造成的。该程序会创建一个新的 AppDomain 来运行迁移。新 AppDomain 的日志记录在原始 AppDomain 中处理(这就是涉及远程处理的原因)。显然,如果单个迁移需要太多时间,记录器就会被 GC 处理。我已经通过用 Console.WriteLine 替换所有记录器调用来验证这一点 - 这使得问题消失了。可以通过更改 migrate.exe 工具来修复(但可能需要更改 EntityFramework 程序集本身)。
【讨论】:
【参考方案4】:我遇到了这个问题,因为我的 web.config 中的连接字符串指向了错误的服务器名称。 实际上,我必须更改我的 c:\windows\system32\drivers\etc\host 文件来为此数据库主机名指定正确的 IP 地址。 只要确保您的数据库服务器是可访问的。
【讨论】:
以上是关于EF 代码第一次迁移报错“对象已断开连接或在服务器上不存在”的主要内容,如果未能解决你的问题,请参考以下文章