实体框架核心迁移 - 连接字符串

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从配置文件中读取它,因为配置文件在应用程序项目中.

Ror*_*eod 5

我所看到的所有示例都涉及对连接字符串进行硬编码或将其放入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)


Ada*_*ent 5

这是我如何做到的,没有很多额外的代码或疯狂。

项目结构:

  • 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.DataDbContext该类的项目。

  • 正常运行迁移命令add-migration init然后update-database


ssp*_*iel 5

假设您的 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)


use*_*414 2

我们遇到了同样的问题并且有解决方案。:)

您必须实现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)

  • 只要您愿意在 IoC 框架之前工作,它就可以正常工作。您本质上必须维护用于解析连接字符串的代码,以独立用于 IoC 和这些工厂。由于您无法将连接字符串提供程序或字符串本身之类的内容注入 IDbContextFactory,因此您必须在工厂中嵌入连接字符串解析代码。无限地复制这个广告,你就会陷入维护噩梦。缺乏注入手段似乎是 EF 团队的重大疏忽。当然有更好的方法。 (2认同)

归档时间:

查看次数:

6795 次

最近记录:

6 年,4 月 前