简体   繁体   English

如何在Visual Studio 2013中自动化Package Manager控制台

[英]How to automate Package Manager Console in Visual Studio 2013

My specific problem is how can I automate "add-migration" in a build process for the Entity Framework. 我的具体问题是如何在Entity Framework的构建过程中自动执行“添加迁移”。 In researching this, it seems the mostly likely approach is something along the lines of automating these steps 在研究这个问题时,似乎最常见的方法是自动化这些步骤

  1. Open a solution in Visual Studio 2013 在Visual Studio 2013中打开解决方案
  2. Execute "Add-Migration blahblah" in the Package Manager Console (most likely via an add-in vsextention) 在程序包管理器控制台中执行“Add-Migration blahblah”(最有可能通过加载项vsextention)
  3. Close the solution 关闭解决方案

This initial approach is based on my own research and this question , the powershell script ultimately behind Add-Migration requires quite a bit of set-up to run. 这个初始方法基于我自己的研究和这个问题 ,最终在Add-Migration背后的powershell脚本需要相当多的设置才能运行。 Visual Studio performs that setup automatically when creating the Package Manager Console and making the DTE object available. Visual Studio在创建程序包管理器控制台并使DTE对象可用时自动执行该设置。 I would prefer not to attempt to duplicate that setup outside of Visual Studio. 我宁愿不尝试在Visual Studio之外复制该设置。

One possible path to a solution is this unanswered stack overflow question 解决方案的一个可能途径是未解决的堆栈溢出问题

In researching the NuGet API, it does not appear to have a "send this text and it will be run like it was typed in the console". 在研究NuGet API时,它似乎没有“发送此文本,它将像在控制台中键入的那样运行”。 I am not clear on the lines between Visual Studio vs NuGet so I am not sure this is something that would be there. 我不清楚Visual Studio与NuGet之间的界限,所以我不确定这是否会存在。

I am able to find the "Pacakage Manager Console" ironically enough via "$dte.Windows" command in the Package Manager Console but in a VS 2013 window, that collection gives me objects which are "Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase". 我能够通过软件包管理器控制台中的“$ dte.Windows”命令找到“Pacakage Manager Console”,但在VS 2013窗口中,该集合为我提供了“Microsoft.VisualStudio.Platform.WindowManagement.DTE”对象。 .WindowBase”。 If there is a way stuff text into it, I think I need to get it to be a NuGetConsole.Implementation.PowerConsoleToolWindow" through reviewing the source code I am not clear how the text would stuffed but I am not at all familiar with what I am seeing. 如果有一种方式填充文本,我想我需要把它变成一个NuGetConsole.Implementation.PowerConsoleToolWindow“通过查看源代码我不清楚文本是如何填充但我不熟悉我的内容我看到了。

Worst case, I will fall back to trying to stuff keys to it along the lines of this question but would prefer not to since that will substantially complicate the automation surrounding the build process. 最糟糕的情况是,我会回过头来尝试按照这个问题来填充密钥,但是不愿意这样做,因为这会使构建过程周围的自动化大大复杂化。

All of that being said, 所有这些都说,

  1. Is it possible to stream commands via code to the Package Manager Console in Visual Studio which is fully initialized and able to support an Entity Framework "add-migration" command? 是否可以通过代码将命令流式传输到Visual Studio中的Package Manager控制台,该控制台已完全初始化并且能够支持实体框架“add-migration”命令?

Thanks for any suggestions, advice, help, non-abuse in advance, 感谢您提出任何建议,建议,帮助,非滥用,

John 约翰

The approach that worked for me was to trace into the entity framework code starting in with the AddMigrationCommand.cs in the EntityFramework.Powershell project and find the hooks into the EntityFramework project and then make those hooks work so there is no Powershell dependency. 对我有用的方法是从EntityFramework.Powershell项目中的AddMigrationCommand.cs开始跟踪实体框架代码,找到EntityFramework项目的钩子,然后使这些钩子工作,这样就没有Powershell依赖。

You can get something like... 你可以得到像......

    public static void RunIt(EnvDTE.Project project, Type dbContext, Assembly migrationAssembly, string migrationDirectory,
        string migrationsNamespace, string contextKey, string migrationName)
    {
        DbMigrationsConfiguration migrationsConfiguration = new DbMigrationsConfiguration();
        migrationsConfiguration.AutomaticMigrationDataLossAllowed = false;
        migrationsConfiguration.AutomaticMigrationsEnabled = false;
        migrationsConfiguration.CodeGenerator = new CSharpMigrationCodeGenerator(); //same as default
        migrationsConfiguration.ContextType = dbContext; //data
        migrationsConfiguration.ContextKey = contextKey;
        migrationsConfiguration.MigrationsAssembly = migrationAssembly;
        migrationsConfiguration.MigrationsDirectory = migrationDirectory;
        migrationsConfiguration.MigrationsNamespace = migrationsNamespace;

        System.Data.Entity.Infrastructure.DbConnectionInfo dbi = new System.Data.Entity.Infrastructure.DbConnectionInfo("DataContext");
        migrationsConfiguration.TargetDatabase = dbi;

        MigrationScaffolder ms = new MigrationScaffolder(migrationsConfiguration);

        ScaffoldedMigration sf = ms.Scaffold(migrationName, false);

    }

You can use this question to get to the dte object and from there to find the project object to pass into the call. 您可以使用此问题到达dte对象,并从那里找到要传递给调用的项目对象。

This is an update to John's answer whom I have to thank for the "hard part", but here is a complete example which creates a migration and adds that migration to the supplied project (project must be built before) the same way as Add-Migration InitialBase -IgnoreChanges would: 这是对约翰答案的更新,我要感谢“困难部分”,但这里有一个完整的例子,它创建了一个迁移并将迁移添加到提供的项目(之前必须构建项目),与Add-Migration InitialBase -IgnoreChanges相同 - Add-Migration InitialBase -IgnoreChanges将:

public void ScaffoldedMigration(EnvDTE.Project project)
{
    var migrationsNamespace = project.Properties.Cast<Property>()
         .First(p => p.Name == "RootNamespace").Value.ToString() + ".Migrations";

    var assemblyName = project.Properties.Cast<Property>()
                           .First(p => p.Name == "AssemblyName").Value.ToString();
    var rootPath = Path.GetDirectoryName(project.FullName);
    var assemblyPath = Path.Combine(rootPath, "bin", assemblyName + ".dll");
    var migrationAssembly = Assembly.Load(File.ReadAllBytes(assemblyPath));
    Type dbContext = null;
    foreach(var type in migrationAssembly.GetTypes())
    {
        if(type.IsSubclassOf(typeof(DbContext)))
        {
            dbContext = type;
            break;
        }
    }

    var migrationsConfiguration = new DbMigrationsConfiguration()
        {
            AutomaticMigrationDataLossAllowed = false,
            AutomaticMigrationsEnabled = false,
            CodeGenerator = new CSharpMigrationCodeGenerator(),
            ContextType = dbContext,
            ContextKey = migrationsNamespace + ".Configuration",
            MigrationsAssembly = migrationAssembly,
            MigrationsDirectory = "Migrations",
            MigrationsNamespace = migrationsNamespace
        };

    var dbi = new System.Data.Entity.Infrastructure
                     .DbConnectionInfo("ConnectionString", "System.Data.SqlClient");
    migrationsConfiguration.TargetDatabase = dbi;

    var scaffolder = new MigrationScaffolder(migrationsConfiguration);
    ScaffoldedMigration migration = scaffolder.Scaffold("InitialBase", true);

    var migrationFile = Path.Combine(rootPath, migration.Directory,
                            migration.MigrationId + ".cs");
    File.WriteAllText(migrationFile, migration.UserCode);
    var migrationItem = project.ProjectItems.AddFromFile(migrationFile);

    var designerFile = Path.Combine(rootPath, migration.Directory,
                           migration.MigrationId + ".Designer.cs");
    File.WriteAllText(designerFile, migration.DesignerCode);
    var designerItem = project.ProjectItems.AddFromFile(migrationFile);
    foreach(Property prop in designerItem.Properties)
    {
        if (prop.Name == "DependentUpon")
            prop.Value = Path.GetFileName(migrationFile);
    }

    var resxFile = Path.Combine(rootPath, migration.Directory,
                       migration.MigrationId + ".resx");
    using (ResXResourceWriter resx = new ResXResourceWriter(resxFile))
    {
        foreach (var kvp in migration.Resources)
            resx.AddResource(kvp.Key, kvp.Value);
    }
    var resxItem = project.ProjectItems.AddFromFile(resxFile);
    foreach (Property prop in resxItem.Properties)
    {
        if (prop.Name == "DependentUpon")
            prop.Value = Path.GetFileName(migrationFile);
    }
}

I execute this in my project template's IWizard implementation where I run a migration with IgnoreChanges , because of shared entites with the base project. 我在项目模板的IWizard实现中执行此操作,我使用IgnoreChanges运行迁移,因为它与基础项目共享。 Change scaffolder.Scaffold("InitialBase", true) to scaffolder.Scaffold("InitialBase", false) if you want to include the changes. 如果要包含更改scaffolder.Scaffold("InitialBase", true)更改为scaffolder.Scaffold("InitialBase", false)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Visual Studio 2013/2015程序包管理器控制台未初始化 - Visual Studio 2013/2015 Package Manager Console not initialized 如何在 Visual Studio 中配置包管理器控制台使用的 powershell 版本? - how to configure the powershell version used by the package manager console in visual studio? 如何在Visual Studio中更改程序包管理器控制台的字体大小 - How to change Font Size of Package Manager Console in Visual Studio 如何在 Visual Studio 外使用包管理器控制台 powershell - How to use Package Manager Console powershell outside visual studio Visual Studio 包管理器控制台的键盘快捷键? - Keyboard Shortcut for the Visual Studio Package Manager Console? 在扩展中以编程方式访问visual studio的powershell控制台(包管理器控制台) - Access the powershell console (package manager console) of visual studio programmatically in an extension 如何在Visual Studio 2013中的C ++项目中编译和链接谷歌测试,但是NuGet包管理器安装了Gtest? - How to compile and link google tests in C++ project in Visual Studio 2013 but with Gtest installed by NuGet Package Manager? 如何在 Visual Studio package 管理器中隐藏 package - How to hide a package in Visual Studio package manager NuGet(NuPack)intellisense(Visual Studio包管理器控制台) - NuGet (NuPack) intellisense (Visual Studio Package Manager Console) 在Visual Studio的Package Manager控制台中调用用户定义的函数 - Calling user defined functions in Package Manager Console in Visual Studio
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM