EF代码第一次迁移错误"对象已断开连接或在服务器上不存在"

d51*_*512 12 entity-framework ef-migrations

我在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)
Run Code Online (Sandbox Code Playgroud)

迁移的目的是更新数据库中存储某些二进制数据的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;
}
Run Code Online (Sandbox Code Playgroud)

我已经看过这个五岁的帖子了,它链接到的文章似乎不再存在了.至少我找不到他们.

有谁知道这里发生了什么?

- 更新 -
这似乎与迁移运行的时间有关.我创建了一个除了睡了22分钟之外什么都没做的迁移

public override void Up()
{
    System.Threading.Thread.Sleep(1320000);
}
Run Code Online (Sandbox Code Playgroud)

我得到了同样的错误.所以这似乎是超时的事情.我不是100%他们所指的服务器上的对象,我在这个问题上找不到太多,因为它与代码首次迁移有关.

我尝试将CommandTimeout迁移Configuration.cs文件中的属性设置为5000,但它没有帮助.我还尝试将SQL Server的Remove query timeout设置设置为0以防止任何超时,但它也没有帮助.

Roa*_*lnz 7

从[GitHub EntityFramework 6 Issue#96] [ https://github.com/aspnet/EntityFramework6/issues/96#issuecomment-289782427]挖走

问题是ToolLogger租约生存期(基类MigrationsLogger是MarshalByRefObject)是默认值(5分钟).ToolingFacade创建记录器,它位于主程序的app域中.迁移在不同的应用程序域中运行.如果迁移时间超过5分钟,则尝试记录任何进一步的信息会导致此错误.解决方案是增加主程序中的租约寿命.所以...在主程序中,在创建ToolingFacade之前,将租约生存期设置为更长的时间段:

using System.Runtime.Remoting.Lifetime;
...
LifetimeServices.LeaseTime = TimeSpan.FromHours(1);
Run Code Online (Sandbox Code Playgroud)

  • 一个小提示:将此文件放在您的迁移文件中,因为这适用于整个应用程序域.这将确保仅在应用新迁移时使用它. (3认同)
  • 您所说的“迁移”文件是什么意思。您是指单个迁移文件还是迁移配置文件?在任何一种情况下,这都不能防止该错误。 (2认同)

Pie*_*one 5

这是一个已知问题对于需要很长时间才能完成的脚本,

解决方法是通过Update-Database命令仅生成 SQL 脚本,并直接在 SQL Server 上执行生成的 SQL。为了仅生成 SQL,您必须使用以下-Script标志:

Update-Database -Script
Run Code Online (Sandbox Code Playgroud)

  • 如果它确实生成了有效的脚本,那将是一个很好的解决方法。根据我的经验,生成的脚本经常缺少 GO 语句,导致脚本在没有手动干预的情况下无法运行。 (2认同)

小智 1

这一直让我们很头疼。该问题似乎是由于 EF 迁移实用程序的设计造成的。该程序创建一个新的 AppDomain 在其中运行迁移。新 AppDomain 的日志记录在原始 AppDomain 中处理(这就是涉及远程处理的原因)。显然,如果单个迁移花费太多时间,记录器就会被 GC 处理。我已经通过用 Console.WriteLine 替换所有记录器调用来验证这一点 - 这使得问题消失。可能可以通过更改 migrate.exe 工具来修复(但可能需要更改 EntityFramework 程序集本身)。


归档时间:

查看次数:

2784 次

最近记录:

7 年,2 月 前