问题 具有配置的类库中的实体框架7迁移支架


尝试将迁移添加到位于ASP.NET 5类库中的EF7模型。跑步时 dnx . ef migration add mymigration 根据我运行它的项目,会失败,结果不同。

如果我在主项目的文件夹中运行它,它找不到 DbContext,这是有道理的,因为 DbContext 在共享项目中,ef命令可能不关心依赖项。

如果我在共享项目的文件夹中运行它,它就无法访问startup.cs中指定的连接字符串。我从像这样的问题中收集到了 这个 如果您在中指定连接字符串,它确实可以从共享项目中工作 OnConfiguring 的方法 DbContext 但我真的希望将此代码与配置分开。

我遇到了一些 问题日志 在EF7存储库中提到他们实现了用于指定项目和上下文的命令行选项,但没有示例,我无法通过查看提交历史记录中的源代码来弄清楚如何使用它。


8711
2018-06-16 13:26


起源

你在哪里存储连接字符串?它是否硬编码到Startup.cs中? - Shaun Luttin
它位于config.json中,并将Configuration加载到AddDbContext <T>中 - CuddleBunny


答案:


这是一种可能适合您的方法。

如果我在共享项目的文件夹中运行它,它就无法访问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 通过使用您在中使用的相同模式 Startup 类。也就是说,在 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连接字符串的东西,那么你可以使用环境变量或用户机密。


10
2018-06-17 02:12



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