使用配置在类库中进行实体框架7迁移脚手架。

11
尝试为位于ASP.NET 5类库中的EF7模型添加迁移。 运行dnx . ef migration add mymigration会根据运行它的项目而产生不同的结果。
如果在主项目文件夹中运行它,则无法找到DbContext,这是有道理的,因为DbContext位于共享项目中,ef命令可能不关心依赖项。
如果在共享项目文件夹中运行它,则无法访问startup.cs中指定的连接字符串。我从像这样的问题中了解到,如果在DbContextOnConfiguring方法中指定连接字符串,则可以从共享项目中运行它,但我真的想将此代码与配置保持分离。
我在EF7存储库中遇到了一些问题日志,其中提到它们实现了命令行选项来指定项目和上下文,但没有示例,并且我无法通过查看提交历史中的源代码来弄清楚如何使用它。

你把连接字符串存储在哪里?它是硬编码到Startup.cs中的吗? - Shaun Luttin
它位于config.json中,并在AddDbContext<T>中加载到Configuration中。 - CuddleBunny
1个回答

10

这里有一种方法可能适合您。

如果我在共享项目的文件夹中运行它,它将无法访问在startup.cs中指定的连接字符串。

Startup.cs

我假设在您的Startup.cs文件中,您通过访问Configuration而不是硬编码来指定连接字符串。此外,我假设在您的Startup.cs文件的构造函数中,您正在从几个来源设置配置。换句话说,您的Startup.cs可能看起来像这样:

public class Startup
{
    public IConfiguration Config { get; set; }

    public Startup(IHostingEnvironment env)
    {
        var config = new Configuration()
            .AddJsonFile("config.json")
            .AddUserSecrets()
            .AddEnvironmentVariables();

        Config = config;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<MyDbContext>(options =>
            {
                options.UseSqlServer(Config["ConnectionStrings:MyDbContext"]);
            });
    }

    public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
    {
        var db = serviceProvider.GetRequiredService<MyDbContext>();
        db.Database.AsSqlServer().EnsureCreated();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    }
}

config.json

另外,我假定您将连接字符串添加到项目根目录下的config.json中(或者通过用户机密或环境变量添加)。您的config.json可能如下所示:

{
  "ConnectionStrings": {
    "MyDbContext": "Some-Connection-String"
  }
}

如果你没有这样做过,尝试一下也许会有好处。

我从类似这样的问题中获悉,如果你在 DbContext 的 OnConfiguring 方法中指定连接字符串,它确实可以从共享项目中起作用,但我真的希望将此代码与配置分开。

DbContext

如果我的假设是正确的,那么您可以通过在 DbContext 构造函数中设置 IConfiguration 来访问连接字符串。然后,在 OnConfiguring 中访问连接字符串。可能看起来像这样:

public class MyDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<SomeModel>().Key(e => e.Id);
        base.OnModelCreating(builder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var connString = Config["ConnectionStrings:MyDbContext"];
        optionsBuilder.UseSqlServer(connString);
    }

    public IConfiguration Config { get; set; }

    public MyDbContext()
    {
        var config = new Configuration()
            .AddJsonFile("config.json")
            .AddEnvironmentVariables();

        Config = config;
    }
}

项目结构

当然,你需要在共享项目文件夹的根目录下拥有一个 config.json 文件。因此,你的项目结构可能看起来像这样:

SharedDataContext
    Migrations
    config.json
    project.json

WebApp
    config.json
    project.json
    Startup.cs

在上面的例子中,两个 config.json 文件都包含 DbContext 的连接字符串设置。

一些想法

如果您不喜欢重复 config.json 中的连接字符串内容,那么可以使用环境变量或用户密码来代替。


这比将整个命名空间移动到主项目中要好得多。迁移添加完美,但应用时遇到了一些问题:由于我使用了自定义的 DataDirectory,所以必须进行一些上下文检测。当从命令行运行时,Path.GetFullPath("..\\MainProject") 给出的是 "C:\Path\To\My\Project\src\MainProject",但实际运行项目时,我得到的是 "C:\Program Files (x86)\MainProject"!因此,我添加了一个检查来查看路径是否包含文本 "src",现在它可以正常工作了。这也应该适用于生产环境,因为环境变量将覆盖所有内容。 - CuddleBunny
我会接受这个答案,直到有更好的解决方案出现。 - CuddleBunny
@CuddleBunny,我很高兴它能够正常工作,并期待着看到更少hacky的东西。也许EF团队的某个人会贡献一个答案。 - Shaun Luttin
3
在beta5版中,他们更改了Config接口以要求基本路径,而我通常会从IApplicationEnvironment.ApplicationBasePath中获取。 问题是当我将IApplicationEnvironment添加到构造函数中时,在运行“ef migration add”时会出现错误,指出没有默认构造函数。 我想知道硬编码路径或连接字符串是否如此糟糕。 虽然这一切都非常hacky和不幸 :( 谁会将他们的上下文放在与Web相同的项目中? 为什么会发生这种疏忽? - Ryan Langton
对于 BasePath 值,您可以使用相对路径语法 @".";例如 var configurationBuilder = new ConfigurationBuilder(@".\", null); 或 @"..\MyStartupProject"。 - ulty4life

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接