我一直是面向数据库的程序员,所以直到今天,我一直使用数据库驱动的方法进行编程,并且我对T-SQL和SQL Server充满信心。
我正在尝试把头放在Entity Framework 6的代码优先方法上-坦率地说-我正在苦苦挣扎。
我有一个现有的数据库-所以我做了一个,Add New Item > ADO.NET Entity Data Model > Code-First from Database
然后得到了一堆代表现有数据库的C#类。到目前为止,一切都很好。
我现在要尝试的是探索如何处理正在进行的数据库升级-既包括模式,也包括“静态”(预填充)查找数据。我的第一个抱怨是使用Fluent API配置了从数据库反向工程的实体,而对我来说,创建自己想创建为带有数据注释的C#类的新表似乎更为自然。“混合”这两种方法是否有任何问题?还是我可以告诉逆向工程步骤只使用数据注释属性,而不是完全使用Fluent API?
我的第二个甚至更大的抱怨:我正在尝试创建不错的迁移和较小的迁移-我要添加的每组功能(例如新表,新索引,一些新列等)每个迁移-但看来我只能进行一次“待定”迁移……当我进行一次迁移时,我进一步修改了模型类,然后尝试使用进行第二次迁移add-migration (name of migration)
,我受到了欢迎:
无法进行显式迁移,因为以下显式迁移正在处理中:[201510061539107_CreateTableMdsForecast]。在尝试生成新的显式迁移之前,请应用未决的显式迁移。
严重地 ?!?!?我不能有一个以上的单个挂起迁移?我要添加的update-database
每个微小迁移都需要运行吗?
似乎是一个很大的缺点!我宁愿创建10个,20个小型,紧凑,易于理解的迁移,然后一口气将它们全部应用-没办法!真的很难相信.....可以解决这个问题吗?
的确,在开发期间一次只能打开一个待处理的迁移。要了解原因,您必须了解如何生成迁移。生成器通过将数据库(架构)的当前状态与模型代码的当前状态进行比较来工作。然后,它有效地创建一个“脚本”(C#类),该脚本可更改数据库的模式以匹配该模型。您可能不想同时拥有多个挂起的脚本,否则脚本将相互冲突。让我们举一个简单的例子:
假设我有一堂课Widget
:
class Widget
{
public int Id { get; set; }
public string Name { get; set; }
}
和Widgets
数据库中的匹配表:
Widgets
-------
Id (int, PK, not null)
Name (nvarchar(100), not null)
现在,我决定向Size
班级添加一个新属性。
class Widget
{
public int Id { get; set; }
public string Name { get; set; }
public int Size { get; set; } // added
}
创建迁移时,生成器会查看我的模型,将其与数据库进行比较,然后看到我的Widget
模型现在具有Size
属性,而相应的表没有Size
列。因此,最终的迁移看起来像这样:
public partial class AddSizeToWidget : DbMigration
{
public override void Up()
{
AddColumn("dbo.Widgets", "Size", c => c.Int());
}
public override void Down()
{
DropColumn("dbo.Widgets", "Size");
}
}
现在,假设允许在第二个迁移仍未完成时创建第二个迁移。我尚未运行Update-Database
命令,因此我的基准数据库架构仍然相同。现在我决定到另一个属性添加Color
到Widget
。
当我为此更改创建迁移时,生成器将我的模型与数据库的当前状态进行比较,并看到我添加了两列。因此,它创建了相应的脚本:
public partial class AddColorToWidget : DbMigration
{
public override void Up()
{
AddColumn("dbo.Widgets", "Size", c => c.Int());
AddColumn("dbo.Widgets", "Color", c => c.Int());
}
...
}
因此,现在我有两个待处理的迁移,并且它们都将Size
在最终运行时尝试向数据库添加一列。显然,这是行不通的。这就是为什么一次只允许一个未决迁移被打开的原因。
因此,开发过程中的一般工作流程为:
如果输入有误,则可以使用命令的–TargetMigration
参数将数据库回滚到先前的迁移Update-Database
,然后从项目中删除错误的迁移并生成一个新的迁移。(如果您确实愿意,可以使用此方法将几个小的迁移组合成一个较大的块,尽管我发现在实践中这是不值得的)。
Update-Database –TargetMigration PreviousMigrationName
现在,当需要更新生产数据库时,您不必一次手动应用每个迁移。那就是迁移的美妙之处-每当您对数据库运行更新的代码时,它们都会自动应用。在初始化期间,EF会查看目标数据库并检查迁移级别(此级别存储在__MigrationHistory
在数据库上启用迁移时创建的特殊表中)。对于尚未应用的代码中的任何迁移,它将全部运行它们以使您更新数据库。
希望这有助于清理问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句