Rob*_*ert 18 c# ef-migrations entity-framework-core .net-core
我在处理数据库连接字符串和迁移时遇到问题.我有2个项目:
该DbContext
是在域项目,所以这是我对运行迁移项目.迁移概念强制我OnConfiguring
在我DbContext
和其中指定数据库提供程序,例如:
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseSqlServer("<connection string>");
}
Run Code Online (Sandbox Code Playgroud)
我的问题是我不想使用硬编码连接字符串,原因很明显,我不能使用ConfigurationManager从配置文件中读取它,因为配置文件在应用程序项目中.
我所看到的所有示例都涉及对连接字符串进行硬编码或将其放入ASP.NET Core应用程序的设置文件中。
如果您不使用ASP.NET Core,或者也许我不知道不想将本地环境的数据库详细信息提交给源代码管理,则可以尝试使用临时环境变量。
首先,IDesignTimeDbContextFactory
像这样实现(注意,IDbContextFactory
现在已弃用):
public class AppContextFactory: IDesignTimeDbContextFactory<AppContext>
{
public AppContextFactory()
{
// A parameter-less constructor is required by the EF Core CLI tools.
}
public AppContext CreateDbContext(string[] args)
{
var connectionString = Environment.GetEnvironmentVariable("EFCORETOOLSDB");
if (string.IsNullOrEmpty(connectionString))
throw new InvalidOperationException("The connection string was not set " +
"in the 'EFCORETOOLSDB' environment variable.");
var options = new DbContextOptionsBuilder<AppContext>()
.UseSqlServer(connectionString)
.Options;
return new AppContext(options);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,可以在调用Update-Database
或任何其他EF Core工具时包括环境变量:
$env:EFCORETOOLSDB = "Data Source=(local);Initial Catalog=ApplicationDb;Integrated Security=True"; Update-Database
Run Code Online (Sandbox Code Playgroud)
这是我如何做到的,没有很多额外的代码或疯狂。
项目结构:
AspNetCoreProject.Web
AspNetCoreProject.Data <-- DbContext 这里
我的 DbContext 是使用构造函数设置的,该构造函数允许您注入 DbContextOptions
AspNetCoreProject.Data
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
}
Run Code Online (Sandbox Code Playgroud)
在您的应用程序或 Web 应用程序中,您可以ConfigureServices
正常设置。
AspNetCoreProject.Web/Startup.cs/ConfigureServices()
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("connection"))
Run Code Online (Sandbox Code Playgroud)
现在,迁移呢?好吧,我“欺骗”了 Visual Studio UI 使其按预期工作。
首先,确保您的应用程序(AspNetCoreProject.Web
带有 的项目Startup.cs
)是启动项目。
其次,打开您的 Nuget 包管理器控制台。在 Nuget PM> 控制台的顶部,有一个“设置默认项目”的下拉菜单,将其指向您AspNetCoreProject.Data
或DbContext
该类的项目。
正常运行迁移命令。 add-migration init
然后update-database
假设您的 DbContext 类具有接受 DbContextOptions 类型的参数的构造函数,则 dotnet ef 命令具有对此场景的本机支持 - 无需更改代码,也无需进行其他配置。创建和运行迁移时只需使用“--startup-project”和“--project”参数。
例如,假设您有一个包含配置的“应用程序”项目和一个名为“域”的单独项目,其中实现了 DbContext。
语境:
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
}
Run Code Online (Sandbox Code Playgroud)
启动:
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("connection"))
Run Code Online (Sandbox Code Playgroud)
CLI 命令:
dotnet ef database update --startup-project Application --project Domain
Run Code Online (Sandbox Code Playgroud)
我们遇到了同样的问题并且有解决方案。:)
您必须实现IDbContextFactory<TContext>
这样做时,您可以从 appsettings.json 中读取连接字符串。您还可以使用 Add-Migration 而不会出现错误,因为OnConfigure()
那时覆盖已经过时了。
示例实现:
public class DomainContextFactory : IDbContextFactory<DomainContext>
{
public string BasePath { get; protected set; }
public DomainContext Create()
{
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var basePath = AppContext.BaseDirectory;
return Create(basePath, environmentName);
}
public DomainContext Create(DbContextFactoryOptions options)
=> Create(options.ContentRootPath, options.EnvironmentName);
private DomainContext Create(string basePath, string environmentName)
{
BasePath = basePath;
var configuration = Configuration(basePath, environmentName);
var connectionString = ConnectionString(configuration.Build());
return Create(connectionString);
}
private DomainContext Create(string connectionString)
{
if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentException($"{nameof(connectionString)} is null or empty", nameof(connectionString));
}
var optionsBuilder = new DbContextOptionsBuilder<DomainContext>();
return Configure(connectionString, optionsBuilder);
}
protected virtual IConfigurationBuilder Configuration(string basePath, string environmentName)
{
var builder = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("constr.json")
.AddJsonFile($"constr.{environmentName}.json", true)
.AddEnvironmentVariables();
return builder;
}
protected virtual string ConnectionString(IConfigurationRoot configuration)
{
string connectionString = configuration["ConnectionStrings:DefaultConnection"];
return connectionString;
}
protected virtual DomainContext Configure(string connectionString, DbContextOptionsBuilder<DomainContext> builder)
{
builder.UseSqlServer(connectionString, opt => opt.UseRowNumberForPaging());
DomainContext db = new DomainContext(builder.Options);
return db;
}
DomainContext IDbContextFactory<DomainContext>.Create(DbContextFactoryOptions options)
=> Create(options.ContentRootPath, options.EnvironmentName);
}
Run Code Online (Sandbox Code Playgroud)
我们如何使用它:
public override IServiceResult<IList<Datei>> LoadAllData()
{
using (var db = this.DomainContextFactory.Create())
{
var files = db.Datei
.ToListAsync<Datei>();
return new ServiceResult<IList<Datei>>(files.Result, files.Result.Count);
}
}
Run Code Online (Sandbox Code Playgroud)
示例配置
{
"ConnectionStrings": {
"DefaultConnection": "Put your connectionstring here"
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6795 次 |
最近记录: |