我的具体问题是如何在Entity Framework的构建过程中自动执行“添加迁移”。在研究这个问题时,似乎最有可能的方法是自动执行这些步骤
这个初始方法基于我自己的研究和this question,最终在Add-Migration背后的powershell脚本需要相当多的设置才能运行。 Visual Studio在创建程序包管理器控制台并使DTE对象可用时自动执行该设置。我不想尝试在Visual Studio之外复制该设置。
解决方案的一个可能途径是未应答的堆栈溢出question
在研究NuGet API时,它似乎没有“发送此文本,它将像在控制台中输入一样运行”。我不清楚Visual Studio与NuGet之间的界限,所以我不确定这是否会存在。
我能够通过软件包管理器控制台中的“$ dte.Windows”命令找到“Pacakage Manager Console”,但在VS 2013窗口中,该集合为我提供了“Microsoft.VisualStudio.Platform”对象。 WindowManagement.DTE.WindowBase”。如果有一种方式填充文本,我认为我需要将它变为NuGetConsole.Implementation.PowerConsoleToolWindow“通过查看source code我不清楚文本将如何填充但我根本不熟悉我所看到的。
最糟糕的情况是,我会回到试图按照this question的方式填写密钥,但不愿意这样做,因为这会使构建过程周围的自动化大大复杂化。
所有这一切,
感谢您提前提出任何建议,建议,帮助,非滥用行为,
约翰
答案 0 :(得分:5)
对我有用的方法是从EntityFramework.Powershell项目中的AddMigrationCommand.cs开始跟踪实体框架代码,找到EntityFramework项目中的钩子,然后使这些钩子工作,这样就没有Powershell依赖
你可以得到类似......
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);
}
您可以使用this question访问dte对象,然后从那里找到要传递给调用的项目对象。
答案 1 :(得分:0)
这是对约翰回答的更新,我要感谢"困难部分",但这里有一个完整的示例,它创建了一个迁移并将迁移添加到提供的项目中(必须以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);
}
}
我在我的项目模板的IWizard
实施中执行此操作,我在IgnoreChanges
运行迁移,因为与基础项目共享参与者。如果要包含更改,请将scaffolder.Scaffold("InitialBase", true)
更改为scaffolder.Scaffold("InitialBase", false)
。