本文依赖
前言
为了节省读者的时间, 这里大概罗列一下本文的知识点
- efCore支持修改表名
- 修改项目启动方式, 添加支持命令行参数
- 根据运行环境不同而使用不同的配置文件
- 每次启动项目时, 同步已有migrations到数据库
框架完善
efCore支持修改表名
就目前的代码, 执行migrations时, 是无法自定义表名的, 会以model的类名做完表名, 如下图:
回顾上回创建的migrations和对应的数据库表名, 是直接取的model的类名作为表名, 那如果支持自定义表名, 该怎么修改呢?
很简单! 类名前, 加个装饰器即可[Table("表名")]
, 修改后, 效果如下:
修改项目启动方式, 添加支持命令行参数
目前执行启动项目只可通过dotnet run
的方式, 然后其他配置默认从appsetting.json中读取, 如果需要在指令中加入其他参数, 目前支持得不够完善
program.cs解读
原program.cs代码如下:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
CreateHostBuilder方法功能主要是根据命令行的args参数进行对应配置, 并返回一个IHostBuilder对象
这里稍作修改
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace test
{
public class Program
{
public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder()
// #手动高亮# 将指令中的内容, 加到运行配置里
.AddCommandLine(args)
.Build();
//get binding
var bind = configuration["bind"] ?? "http://localhost:5052/";
var app = new WebHostBuilder()
//使用kestrel
.UseKestrel(options =>
{
options.Limits.MaxRequestBodySize = 200 * 1024 * 1024;
})
//项目运行目录
.UseContentRoot(Directory.GetCurrentDirectory())
//log
.ConfigureLogging(logger => logger.SetMinimumLevel(LogLevel.Debug))
//监听地址和端口
.UseUrls(bind)
//注入启动项
.UseStartup<Startup>();
app.Build().Run();
}
}
}
这时执行migration指令, 会报以下错误
Unable to create an object of type 'TestContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
解决方案:
TestContext同级目录下, 新建DesignTimeDbContextFactory
类, 内容如下:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
namespace test.Models
{
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<TestContext>
{
public DemoContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<TestContext>();
var connectionString = "数据库连接串";
optionsBuilder.UseMySql(
connectionString,
new MySqlServerVersion(new System.Version(8, 0, 17)),
options =>
{
options.CharSetBehavior(CharSetBehavior.NeverAppend);
options.MigrationsAssembly("test");
});
return new TestContext(optionsBuilder.Options);
}
}
}
结果如下图所示, 成功修改启动路径
下面是上述代码中手动高亮的注释:
根据运行环境不同而使用不同的配置文件
在上述改动中, main方法中app.Build().Run();
前, 加入以下代码
app.ConfigureAppConfiguration((context, configBuilder) =>
{
//获取环境变量
var env = context.HostingEnvironment;
//添加环境路径
configBuilder.AddJsonFile(configPath, true, true);
//非正式环境, 则添加对应环境变量名的appsetting.json
if (!env.IsProduction())
{
Console.WriteLine($"######### appsettings.{env.EnvironmentName}.json");
configBuilder.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true);
#if DEBUG
configBuilder.AddEnvironmentVariables();
#endif
//添加命令参数
if (args?.Length > 0)
{
configBuilder.AddConfiguration(configuration);
}
}
});
启动项目时, 同步已有migrations到数据库
前面说到了ef指令的使用, 包括如何将生成的migrations应用到数据库, 但是使用命令行的方式, 还存在以下情况, 可能会导致migrations无法执行:
- 无法直连服务器或者无法在服务器上执行ef指令
- 服务器上未安装ef指令的依赖包
因此, 如果能在项目启动时, 能通过代码将已有的migrations同步到数据库, 就更好不过了
主要修改的文件:Startup.cs
- 修改
Startup.cs
中的Configure
方法定义public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
Configure
方法中添加以下代码using (var serviceScope = app.ApplicationServices.CreateScope()) //手动高亮 { serviceScope.ServiceProvider.GetService<TestContext>().Database.Migrate(); //手动高亮 }
- 运行代码
dotnet run
(根据实际情况, 觉得是否需要添加其他指令参数) - 查看是否生效(已生效)
实例代码
最后附上上述流程后产生的实例代码