2016-08-18 39 views
2

我在当前项目中一直使用EF迁移一段时间,并且所有工作都很棒,直到今天,情况如下:EF 6 CodeFirst添加迁移脚手架并生成不存在的更改

  1. 我做了添加一个字符串属性
  2. 我打电话的API函数的小变化,并得到了有变化模型
  3. 我跑的命令是错误的“添加迁移MigrationXYZ”
  4. 一新的迁移是在没有发生额外变化的情况下创建的

我跑了“添加迁移MigrationXYZ - 强制”,以确保它不是一个有一点问题,我放弃了DB,重启VS(2015),但都是一样的

的另一个问题是,即使如果我使用脚手架完成的迁移,错误仍会返回说“无法更新数据库以匹配当前模型,因为有待处理的更改...”

查看这些更改后,它们都只是一个关于具有[Required]属性的字符串属性和脚手架需要使其可以为空,下面是一个示例。

public partial class MigrationXYZ: DbMigration 
{ 
    public override void Up() 
    { 
     AddColumn("dbo.Foos", "NewProperty", c => c.String());//<-- Expected Change 
     AlterColumn("dbo.Bars", "Name", c => c.String());//<-- Unexpected Change 
    } 

    public override void Down() 
    { 
     AlterColumn("dbo.Bars", "Name", c => c.String(nullable: false));//<-- Unexpected Change 
     DropColumn("dbo.Foos", "NewProperty");//<-- Expected Change 
    } 
} 

public class Bar 
{ 
    //This was not touched in ages, some even before adding the first migration 
    [Required] 
    public string Name { get; set; } 
} 

现在我坚持,不知道如何在移动状态解决这个问题...腐败

编辑

我一直在试图调试Add-Migration命令理解EF为什么看到模型与实际不同,但是当您拥有需要签名DLL的​​Identity等依赖项时,使用EF源是不可能的。

但是更多的研究使我这导致this blog post通过@trailmax和破译迁移哈希代码answer here,并与在EF源一点点搜索我做了一个小的应用程序来提取这两种当前模型和最后一个迁移模型进行比较。

代码即可获得当前的模型表示的XML

//Extracted from EF Source Code 
public static class DbContextExtensions 
{ 
    public static XDocument GetModel(this DbContext context) 
    { 
     return GetModel(w => EdmxWriter.WriteEdmx(context, w)); 
    } 

    public static XDocument GetModel(Action<XmlWriter> writeXml) 
    { 
     using (var memoryStream = new MemoryStream()) 
     { 
      using (var xmlWriter = XmlWriter.Create(
       memoryStream, new XmlWriterSettings 
       { 
        Indent = true 
       })) 
      { 
       writeXml(xmlWriter); 
      } 

      memoryStream.Position = 0; 

      return XDocument.Load(memoryStream); 
     } 
    } 
} 

     //In Program.cs 
     using (var db = new DbContext()) 
     { 
      var model = db.GetModel(); 
      using (var streamWriter = new StreamWriter(@"D:\Current.xml")) 
      { 
       streamWriter.Write(model); 
      } 
     } 

的代码来提取迁移模型在XML

//Code from Trailmax Tech Blog 
public class MigrationDecompressor 
{ 
    public string ConnectionString { get; set; } 

    public String DecompressMigrationFromSource(IMigrationMetadata migration) 
    { 
     var target = migration.Target; 
     var xmlDoc = Decompress(Convert.FromBase64String(target)); 
     return xmlDoc.ToString(); 
    } 

    public String DecompressDatabaseMigration(String migrationName) 
    { 
     var sqlToExecute = String.Format("select model from __MigrationHistory where migrationId like '%{0}'", migrationName); 

     using (var connection = new SqlConnection(ConnectionString)) 
     { 
      connection.Open(); 

      var command = new SqlCommand(sqlToExecute, connection); 

      var reader = command.ExecuteReader(); 
      if (!reader.HasRows) 
      { 
       throw new Exception("Now Rows to display. Probably migration name is incorrect"); 
      } 

      while (reader.Read()) 
      { 
       var model = (byte[])reader["model"]; 
       var decompressed = Decompress(model); 
       return decompressed.ToString(); 
      } 
     } 

     throw new Exception("Something went wrong. You should not get here"); 
    } 

    /// <summary> 
    /// Stealing decomposer from EF itself: 
    /// http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Migrations/Edm/ModelCompressor.cs 
    /// </summary> 
    private XDocument Decompress(byte[] bytes) 
    { 
     using (var memoryStream = new MemoryStream(bytes)) 
     { 
      using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) 
      { 
       return XDocument.Load(gzipStream); 
      } 
     } 
    } 
} 

     //Inside Program.cs 

     var decompresser = new MigrationDecompressor 
     { 
      ConnectionString = "<connection string>" 
     }; 

     var databaseSchemaRecord = decompresser.DecompressDatabaseMigration("<migration name>"); 
     using (var streamWriter = new StreamWriter(@"D:\LastMigration.xml")) 
     { 
      streamWriter.Write(databaseSchemaRecord); 
     } 

不幸的是我仍然无法找到问题,模型和最后一次迁移之间的唯一区别是增加的属性的预期变化,没有出现意想不到的变化,在运行EF建议的迁移之后,然后将当前模型与建议的迁移进行比较,仍然该模型与变更不匹配,但不应该为null的模型仍然不为空,而建议的迁移将其显示为可以为null 。

预期的变化显示

<Property Name="NewProperty" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" /> 
. 
. 
. 
<ScalarProperty Name="NewProperty" ColumnName="NewProperty" /> 
. 
. 
. 
<Property Name="NewProperty" Type="nvarchar(max)" Nullable="true" /> 
+0

我不介意downvote,但是请解释downvote的原因,如果问题不清楚,或者问题的原因非常明显,那么请指出我的答案。 – MEYWD

+0

其他迁移中的Bars.Name'是否有任何更改?我在一个案例中发现手动修改的迁移脚本产生了非常类似的错误。 – trailmax

+0

也在使用什么版本的SQL Server(假设这是SQL Server)?我在开发机器上使用SQL Server 2008 R2时遇到了问题。但是,升级到2014年时,问题消失了 – trailmax

回答

0

嗯,@ trailmax的answer又好看,我想尝试的东西,一个信息,我没有在这个问题包括,并且是因为在其他地方使用而被解雇的原因,在这次迁移中没有被改变,并且被@trailmax也作为原因解雇了,这是属性和特定属性。

我的实际酒吧类看起来像这样

public class Bar 
{ 
    //This was not touched in ages, some even before adding the first migration 
    [Required] 
    [AssertThat(@"<Condition>", ErrorMessage = "Please revise the name")] 
    public string Name { get; set; } 
} 

我注释掉AssertThat属性,你猜怎么着,这不应该存在消失的所有更改。

+0

我敢打赌,如果您现在返回此属性并尝试添加迁移,它会告诉您模型中没有更改,也无需迁移。 – trailmax

+0

@trailmax这就是我的想法,但是当我取消注释代码时,问题返回,我会在有空的时候尝试调查它。 – MEYWD

0

试试你的数据库回滚到以前的人之一,

Update-database -targetMigration "nameofpreviousmigration"

(您可能需要在运行之前运行更新数据库以上我不确定)

然后删除你的新迁移,创建一个全新迁移并运行

update-database

希望这将解决这个问题,它想有一个额外的迁移

另一种选择,但它可能不是太手动编辑迁移,并采取了意想不到的部分

+0

尝试过,尝试删除数据库并再次执行所有迁移,结果相同。 – MEYWD

-1

请重的最佳解决方案使用update-database命令显式提供connectionstring和provider。你可以在连接字符串中找到这些值。

有时,我们可能需要指导实体框架连接到正确的数据库。其中一种情况是,选择错误的项目作为启动项目,这将使实体框架假定连接到默认数据库。

更新数据库-connectionstring:“” -provider:“”

+0

该数据库是正确的,正如问题中所述以及@Ronan对答案的评论所述,我放弃了数据库,并使用了相同的结果进行迁移。 – MEYWD