我在当前项目中使用EF Migrations已经有一段时间了,而且一切都运行良好,直到今天,情况如下:
我运行了“Add-Migration MigrationXYZ -Force”以确保它不是一件事,我放弃了数据库,重新启动了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看到模型与实际不同,但是当你有像Identity这样需要签名的DLL工作的依赖时,使用EF源是不可能的。
然而,另外的研究引导我进入answer here导致this blog post通过@trailmax和解密迁移哈希的代码,并在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的值仍然不为空,而建议的迁移将其显示为可为空。
预期的更改会显示
<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 :(得分:0)
尝试使用
将数据库回滚到之前的数据库 Update-database -targetMigration "nameofpreviousmigration"
(你可能需要在运行上面的内容之前运行update-database我不确定)
然后删除新迁移,创建全新迁移并运行
update-database
。
希望这会解决它认为存在额外迁移的问题
另一种选择,但可能不是最好的解决方案是手动编辑迁移并取出意外的部分
答案 1 :(得分:0)
好吧,再看看@ trailmax&#39; answer,我想尝试一些事情,这个信息我没有包含在这个问题中,并且因为它被用于其他地方,在这次迁移中没有改变,并且也被@trailmax解雇为原因,具体是属性和ExpressiveAnnotations
属性。
我的实际Bar类看起来像这样
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
属性,然后猜测,不应该存在的所有变化都消失了。
答案 2 :(得分:-1)
请尝试使用update-database命令显式提供connectionstring和provider。您可以在connectionstring中找到这些值。
有时,我们可能需要指示实体框架连接到正确的数据库。其中一个案例是,选择错误的项目作为启动项目,这将使实体框架假设连接到默认数据库。
update-database -connectionstring:“” - 提供者:“”