发布.Net Core RC1应用程序后,project.json中指定的命令具有为其创建的相应.cmd文件,这些文件可在部署后执行(例如web.cmd和ef.cmd)。在我的例子中,我想在我的部署目标上运行以下Entity Framework命令:
dotnet ef database update -c MyContext
当我从包含源代码的文件夹中运行它时,这很好用,但是在发布后,它似乎不会在已编译的DLL中找到命令。我对RC2命令变化的理解是'工具'可以编译为名为dotnet - * .dll的独立应用程序,并可以通过CLI执行。如何将Entity Framework Core工具公开为已发布输出中的可执行DLL?
仅供参考,我的构建/部署工作流程如下:
TeamCity的
dotnet restore => dotnet build => dotnet test => dotnet发布
Octopus Deploy
上传套餐=> EF更新数据库=>等
答案 0 :(得分:8)
我在项目中遇到了同样的问题,但由于多种原因,我不希望迁移在应用程序启动时自动运行。
要解决这个问题,我更新了Program.cs
以获取两个参数(完整代码列在下面)
--ef-migrate
,以应用所有待处理的迁移,以及--ef-migrate-check
,用于验证是否已应用所有迁移如果存在参数,则应用EF操作并退出程序,否则启动Web应用程序。
请注意,它取决于Microsoft.Extensions.CommandLineUtils
包以简化命令行解析。
对于章鱼部署,可以将包发布两次到单独的位置 - 一个用于运行迁移,另一个用于虚拟主机。在我们的例子中,我们添加了一个带有内容
的“post deploy powershell脚本”$env:ASPNETCORE_ENVIRONMENT="#{Octopus.Environment.Name}"
dotnet example-app.dll --ef-migrate
在泊坞广告环境中,它也可以完美地运作
docker run -it "example-app-container" dotnet example-app.dll --ef-migrate
完整的Program.cs,不包括命名空间和使用:
//Remember to run: dotnet add package Microsoft.Extensions.CommandLineUtils
public class Program
{
public static void Main(string[] args)
{
var commandLineApplication = new CommandLineApplication(false);
var doMigrate = commandLineApplication.Option(
"--ef-migrate",
"Apply entity framework migrations and exit",
CommandOptionType.NoValue);
var verifyMigrate = commandLineApplication.Option(
"--ef-migrate-check",
"Check the status of entity framework migrations",
CommandOptionType.NoValue);
commandLineApplication.HelpOption("-? | -h | --help");
commandLineApplication.OnExecute(() =>
{
ExecuteApp(args, doMigrate, verifyMigrate);
return 0;
});
commandLineApplication.Execute(args);
}
private static void ExecuteApp(string[] args, CommandOption doMigrate, CommandOption verifyMigrate)
{
Console.WriteLine("Loading web host");
var webHost = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
if (verifyMigrate.HasValue() && doMigrate.HasValue())
{
Console.WriteLine("ef-migrate and ef-migrate-check are mutually exclusive, select one, and try again");
Environment.Exit(2);
}
if (verifyMigrate.HasValue())
{
Console.WriteLine("Validating status of Entity Framework migrations");
using (var context = webHost.Services.GetService<DatabaseContext>())
{
var pendingMigrations = context.Database.GetPendingMigrations();
var migrations = pendingMigrations as IList<string> ?? pendingMigrations.ToList();
if (!migrations.Any())
{
Console.WriteLine("No pending migratons");
Environment.Exit(0);
}
Console.WriteLine("Pending migratons {0}", migrations.Count());
foreach (var migration in migrations)
{
Console.WriteLine($"\t{migration}");
}
Environment.Exit(3);
}
}
if (doMigrate.HasValue())
{
Console.WriteLine("Applyting Entity Framework migrations");
using (var context = webHost.Services.GetService<DatabaseContext>())
{
context.Database.Migrate();
Console.WriteLine("All done, closing app");
Environment.Exit(0);
}
}
// no flags provided, so just run the webhost
webHost.Run();
}
}
答案 1 :(得分:2)
有一个非常有用的帖子可以解决这个问题here。
它对我有用(我不得不稍微调整一下命令,但它给了我一个良好的基础开始)。
总之:您可以通过传递dotnet ef database update
来复制ef.dll
命令(例如直接来自您的nuget文件夹(或者如果您没有nuget,则可以从其他地方复制),因为您正在进行刺激机器..))你的.dll包含带有一些附加参数的迁移(见下文)到dotnet.exe
(或linux等价物)。
为了完整性,这里是.cmd(也来自博客帖子!)
set EfMigrationsNamespace=%1
set EfMigrationsDllName=%1.dll
set EfMigrationsDllDepsJson=%1.deps.json
set DllDir=%cd%
set PathToNuGetPackages=%USERPROFILE%\.nuget\packages
set PathToEfDll=%PathToNuGetPackages%\microsoft.entityframeworkcore.tools.dotnet\1.0.0\tools\netcoreapp1.0\ef.dll
dotnet exec --depsfile .\%EfMigrationsDllDepsJson% --additionalprobingpath %PathToNuGetPackages% %PathToEfDll% database update --assembly .\%EfMigrationsDllName% --startup-assembly .\%EfMigrationsDllName% --project-dir . --content-root %DllDir% --data-dir %DllDir% --verbose --root-namespace %EfMigrationsNamespace%
(如果此cmd位于博客帖子中,则为bash版本)
顺便说一下。在许多github问题中也提到了这种方法:https://github.com/aspnet/EntityFramework.Docs/issues/328 https://github.com/aspnet/EntityFramework.Docs/issues/180
ps:我在blog of Ben Day中找到了这个,所以归功于Ben!
答案 2 :(得分:1)
不幸的是, EF Core迁移文件很多……我已经看到了很多解决方案,但让我们列出其中的解决方案。因此,这是您可以在没有Visual Studio的情况下运行和部署EF迁移的方法。 以下都不是完美的解决方案,但都需要注意以下几点:
IDesignTimeDbContextFactory<DbContext>
接口以使其工作。另外,请确保您在部署服务器上具有 EF.dll 和 Microsoft.EntityFrameworkCore.Design.dll 。链接的脚本正在大量文件夹中寻找它们。最好是在构建过程中将其从.nuget文件夹复制到工件。听起来很复杂,是的...但是链接脚本有很大帮助。dbContext.Database.Migrate();
抱歉,列表很长。但希望能有所帮助。
答案 3 :(得分:0)
在我的背景下,我收到了来自here的这个骇客
// Hack added so EntityFrameworkCore\Add-Migration initial works
public class ApplicationContextDbFactory : IDesignTimeDbContextFactory<MyContext>
{
MyContext IDesignTimeDbContextFactory<MyContext>.CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
optionsBuilder.UseSqlServer(configuration.GetConnectionString("StreamCheckpointContextDB"));
return new MyContext(optionsBuilder.Options);
}
}
我编写了程序。Main的内容如下:
public static void Main(string[] args)
{
if (args.Contains("JustMigrateMe"))
{
IDesignTimeDbContextFactory<MyContext> factory = new ApplicationContextDbFactory();
var ctx = factory.CreateDbContext(new string[0]);
ctx.Database.Migrate();
ctx.Dispose();
return;
}
// Other stuff
}
}
因此,要应用迁移,我只需使用添加的参数调用exe。
答案 4 :(得分:0)
对于EF Core 3.1,我在发布文件文件夹中成功运行了以下代码行。当然,可以使用以下方式调整MyUser的路径
dotnet exec --depsfile ProjectName.deps.json --runtimeconfig ProjectName.runtimeconfig.json C:\ Users \ MyUser.nuget \ packages \ dotnet-ef \ 3.1.9 \ tools \ netcoreapp3.1 \ any \ tools \ netcoreapp2.0 \ any \ ef.dll 数据库更新--context MyContext --assembly Project.dll-详细