EF代码优先迁移错误"对象已断开连接或在服务器上不存在"
EF代码优先迁移错误"对象已断开连接或在服务器上不存在"
我在SQL Server 2008上使用Entity Framework 6.1.1,并且我有一个长时间运行的代码优先迁移(约20分钟)。它到最后时出现以下错误。
System.Runtime.Remoting.RemotingException: 对象“/f10901d8_94fe_4db4_bb9d_51cd19292b01/bq6vk4vkuz5tkri2x8nwhsln_106.rem”已断开连接或在服务器上不存在。 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) ...
迁移的目的是更新数据库中存储一些二进制数据的MIME类型字段。它遍历每一行,读取二进制数据,尝试确定内容的类型,然后将相应的MIME类型值写入该行。
下面的脚本使用ADO.NET生成要运行的更新语句列表。我使用ADO.NET是因为我必须使用.NET的图像处理库(System.Drawing.Imaging.ImageFormat)来确定每行中的二进制内容的类型(它将是jpeg、png或pdf)。
public override void Up() { ListupdateStatements = new List (); 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; }
我看到了这篇五年前的帖子,并且它链接的文章似乎已经不存在了。至少我找不到它们。
有人知道这里发生了什么吗?
-- 更新 --
这似乎与迁移运行的时间有关。我创建了一个完全无操作的迁移,只是睡眠22分钟
public override void Up() { System.Threading.Thread.Sleep(1320000); }
然后我得到了相同的错误。所以这似乎是一个超时的问题。我不确定他们所指的服务器上的对象是什么,而且我在与代码优先迁移相关的这个问题上找不到太多信息。
我尝试将迁移的CommandTimeout
属性设置为5000,但没有帮助。我还尝试将SQL Server的Remove query timeout
设置为0以防止任何超时,但也没有帮助。
EF code first migration error "Object has been disconnected or does not exist at the server"是由于ToolLogger租约生命周期过短导致的问题。ToolLogger是一个MarshalByRefObject基类,其默认租约生命周期为5分钟。ToolingFacade在主程序的应用程序域中创建了日志记录器,而迁移在另一个应用程序域中运行。如果迁移所花费的时间超过5分钟,尝试记录任何进一步的信息将导致此错误。解决方法是在主程序中将租约生命周期设置为较长的时间段。可以在迁移文件中添加以下代码来实现,以确保仅在应用新迁移时使用该设置:
using System.Runtime.Remoting.Lifetime; ... LifetimeServices.LeaseTime = TimeSpan.FromHours(1);
这个解决方法过去曾经使用过,但在6.3版本中可能已经失效了。在EF 6.4中也不能解决这个问题。
EF code first migration error "Object has been disconnected or does not exist at the server"是一个常见的问题,这个问题的出现是由于EF迁移工具的设计问题导致的。该程序在新的AppDomain中运行迁移操作,并且日志记录是在原始的AppDomain中处理的(这就是为什么会涉及到远程调用)。显然,如果单个迁移操作的执行时间过长,日志记录器就会被GC回收。通过将所有的日志记录调用替换为Console.WriteLine,可以解决这个问题。可能需要修改migrate.exe工具来修复这个问题,但这可能需要修改EntityFramework程序集本身。
EF code first migration error "Object has been disconnected or does not exist at the server"是Entity Framework 6中已知的一个问题,出现在执行时间较长的脚本时。
为了解决这个问题,可以通过使用Update-Database
命令只生成SQL脚本,并直接在SQL Server上执行生成的SQL。要仅生成SQL,需要使用-Script
标志:
Update-Database -Script
如果生成的脚本缺少GO语句,则需要手动干预才能使脚本可运行。这是一个很好的解决方法,但是从我的经验来看,生成的脚本经常缺少GO语句。
解决方法如下:
1. 执行Update-Database -Script
命令,生成SQL脚本。
2. 打开生成的SQL脚本,并手动添加缺少的GO语句。
3. 在SQL Server上执行修改后的SQL脚本。
这样就可以解决EF code first migration error "Object has been disconnected or does not exist at the server"问题了。