以编程方式创建代码首次迁移

时间:2015-11-30 15:36:14

标签: c# entity-framework powershell

我正处于一个项目中,我们在实体框架上使用Code First作为我们的数据库。

我们希望更改所有持续集成以使用下游生成的MSI软件包,但使用EF会产生一些复杂性。

我尝试过网络上的各种内容,但大多数内容似乎要求AutomaticMigrations设置为true以及AutomaticMigrationDataLossAllowed(请参阅:http://romiller.com/2012/02/09/running-scripting-migrations-from-code/)。< / p>

我试图通过查看.NET反射器来复制Add-Migration所做的事情,但我似乎无法找到一种方法来调用通过Powershell调用的命令System.Data.Entity.Migrations.AddMigrationCommand

任何人都有任何关于如何在不做极其混乱的情况下接近实现这一目标的想法?这是我认为很多人都想要做的事情......

非常感谢提前!

3 个答案:

答案 0 :(得分:8)

首先,无法在visual studio之外运行Nuget powershell(它使用DTE)。此外,您在没有Visual Studio的情况下编写的所有内容都需要手动插入csproj(但不是一项艰巨的任务)。

为了说明它是如何工作的,我发给你一些代码。 要测试它们,请创建MyDll dll(带有上下文和实体的项目测试),然后使用Enable-Migrations在MyDll上手动启用迁移(仅用于创建Configuration.cs)。

之后,您可以使用这段代码生成源代码

DbConnectionInfo connectionStringInfo = new DbConnectionInfo(
    "Server=.;Database=MigrationTest;User=sa;Password=dacambiare", "System.Data.SqlClient"); // We shoud retrieve this from App.config

ToolingFacade toolingFacade =  new ToolingFacade(
    "MyDll",   // MigrationAssemblyName. In this case dll should be located in "C:\\Temp\\MigrationTest" dir
    "MyDll",  // ContextAssemblyName. Same as above
    null,
    "C:\\Temp\\MigrationTest",   // Where the dlls are located
    "C:\\Temp\\MigrationTest\\App.config", // Insert the right directory and change with Web.config if required
    "C:\\Temp\\App_Data",
    connectionStringInfo)
{
    LogInfoDelegate = s => {Console.WriteLine(s);},
    LogWarningDelegate = s => { Console.WriteLine("WARNING: " + s); },
    LogVerboseDelegate = s => { Console.WriteLine("VERBOSE: " + s); }
};


ScaffoldedMigration scaffoldedMigration = toolingFacade.Scaffold("MyMigName", "C#", "MyAppNameSpace", false);

Console.WriteLine(scaffoldedMigration.DesignerCode);
Console.WriteLine("==================");
Console.WriteLine(scaffoldedMigration.UserCode);

// Don't forget the resource file that is in the scaffoldedMigration

修改
我忘了名称空间并且不经常使用,所以你在这里

using System;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations.Design;

答案 1 :(得分:4)

对您的问题不是真正的答案,而是分享我的经验:我非常小心这样为您生成的迁移。很多时候,当我创建迁移(在VS中)时,我会对它们进行审核。我检查建议的更改是否是我想要的,EF不会尝试做一些愚蠢的事情(比如通过删除表并创建一个新列来重命名列/表)。

有时EF还会遗漏一些重要的变化 - 最近,当我更改nvarchar字段的长度时,我遇到了生成正确迁移的麻烦。这也需要仔细审查迁移。

您的迁移也是代码。我们正在对迁移进行同行评审,然后才能投入生产。自动创建迁移将使这些更改不太明显,并可能导致生产中的数据丢失。

如果您正在努力应对团队环境中的迁移 - 我们通过沟通解决了这个问题:每当开发人员检查新迁移时 - 电子邮件都会发送给此项目中的所有其他开发人员。解决了我们所有的问题。

更新刚刚与同事讨论过,另一个问题出现了 - 您将如何进行本地开发?你会在dev的机器上创建迁移,确保一切正常吗?然后删除迁移并签入代码?然后您的CI将重新生成您的迁移?我认为这会影响开发人员在使用EF时的想法。

答案 2 :(得分:1)

您可以使用System.Data.Entity.Migrations.Design.MigrationScaffolder类以编程方式生成迁移,如下所示:

[TestMethod]
public void GenerateTestMigration()
{
    var config = new MyDbMigrationsConfiguration();
    var scaffolder = new MigrationScaffolder(config);
    var pendingMigration = scaffolder.Scaffold("TestMigration");
    Trace.WriteLine(pendingMigration.UserCode);
}

如果存在挂起的迁移,或者需要像这样创建迁移,我在构建服务器上使用此技术和其他技术来使构建失败:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Design;
using System.Diagnostics;
using System.Linq;

namespace YabbaDabbaDoo
{
    [TestClass]
    public class MigrationTests
    {
        [TestMethod]
        [TestCategory("RunOnBuild")]
        public void VerifyThereAreNoPendingMigrations()
        {
            // Arrange
            var config = new MyDbMigrationsConfiguration();
            var dbMigrator = new DbMigrator(config);

            // Act
            var pendingMigrations = dbMigrator.GetPendingMigrations().ToList();

            // Visual Assertion
            Trace.WriteLine(pendingMigrations);

            // Assert
            Assert.AreEqual(0, pendingMigrations.Count(), "There are pending EF migrations that need to be ran.");
        }

        [TestMethod]
        [TestCategory("RunOnBuild")]
        public void VerifyDatabaseIsCompatibleWithModel()
        {
            // Arrange
            var context = new MyDbContext();

            // Act
            var isCompatible = context.Database.CompatibleWithModel(false);

            // Visual Assertion
            if (!isCompatible)
            {
                var config = new MyDbMigrationsConfiguration();
                var scaffolder = new MigrationScaffolder(config);
                var pendingMigration = scaffolder.Scaffold("MissingMigration");

                Trace.WriteLine("Missing Migration:");
                Trace.WriteLine("");
                Trace.WriteLine(pendingMigration.UserCode);
            }

            // Assert
            Assert.IsTrue(isCompatible, "The EF model is not compatible with the database. An EF migration needs to be created. See output for sample of missing migration.");
        }
    }
}