EntityFramework 7 (EF7) 迁移。 DbContext 和 StartUp Project 在不同的程序集中

EntityFramework 7 (EF7) Migrations. DbContext and StartUp Project are in different assemblies

我正在尝试通过 entityframework.commands 在 EF7 中使用迁移。但是我的 DbContext 与 Start-up 项目处于不同的程序集中(asp.net mvc 是一个启动项目并且 Core.Implementation 有一个 DbContex)。

dnx。 ef 迁移添加 MyMigration -c MyContext

System.InvalidOperationException: 未找到名为 'MyContext' 的 DbContext。

我试过使用命名空间指向其他程序集,但也没有用。有可能吗?或者我只需要将我的上下文放在 ef7 命令所在的程序集中?

每个问题 #639, #2256, #2293, #2294, #2357, #2553 & #2748,我们在该领域有一些工作要做。 :-)

编辑

自 1.0.0-rc1-final(可能更早)以来,此解决方法是不必要的

  • 现在您不需要 App.DataAccess/Startup.cs(如果您使用下面的解决方法,只需将其删除)
  • 你 create/execure 迁移形成了你的主项目(在本例中 App.Web)
  • 但是您必须指定包含迁移的项目(-p 参数):

cd App.Web
dnx ef migrations add NewMigration -p App.DataAccess

如果您有多个数据库上下文,您还必须指定要使用的数据库上下文(-c 参数)

cd App.Web
dnx ef migrations add NewMigration -p App.DataAccess -c YourDbContext

编辑结束

我找到了解决方法

假设您有 2 个项目:App.WebApp.DataAccess

您可以添加一个非常基本的 Startup class 到您的 App.DataAccess:

>App.Web
-->Startup.cs // your main startup
>App.DataAccess
-->path/to/ApplicationDbContext.cs
-->different/path/to/YourModels.cs
-->Startup.cs // add a simple startup class
-->project.json

简单启动class (App.DataAccess\Startup.cs):

using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Data.Entity;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Configuration;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;

namespace App.DataAccess
{
    public class Startup
    {
        public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
        {
            var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
                .AddJsonFile("../App.Web/config.json"); // path to your original configuration in Web project

            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; set; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
        }
    }
}

比 App.DataAccess (App.DataAccess/project.json) 修改你的 project.json:

{
  "version": "1.0.0-*",
  "description": "App.DataAccess Class Library",
  "authors": [ "Author" ],
  "tags": [ "" ],
  "projectUrl": "",
  "licenseUrl": "",
  "frameworks": {
    "dnx451": { }
  },

  "dependencies": {
    "EntityFramework.Commands": "7.0.0-beta7",
    "Microsoft.Framework.Configuration.Json": "1.0.0-beta7",
  },

  "commands": {
    "ef": "EntityFramework.Commands" // this line is important, it will give you access to 'dnx ef' in command line
  }
}

你所要做的就是去 App.DataAccess 并使用 dnx ef:

cd App.DataAccess
dnx ef migrations add NewMigration
dnx ef migrations remove
dnx ef database update
dnx ef ...

对于 ASP.NET Core 1.0 和 EF Core 1.0

假设我们想将上下文移动到 Core1RtmEmptyTest.DataLayer 项目。

首先通过修改其 project.json 文件为该子项目启用 EF 工具:

{
     // same as before

    "tools": {
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": [
                "portable-net45+win8"
            ]
        }
    },

     // same as before
}

然后运行这个新项目的根目录(而不是主项目的根目录)的命令

D:\path\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ migrations add InitialDatabase

这里我们也应该指定startup-project

最后更新数据库

D:\path\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ database update

我有一个解决方法,但我使用的是 EFCore 1.0.0,因此您必须迁移。在代码片段下方,您需要使其正常工作:

想法是拥有一个中央数据上下文:MigrationsDataContext 来处理整个数据库迁移。因此,您可以将此迁移放在一个专门用于迁移数据库的单独项目中。您只需 MigrationsDataContext 查看包含所需数据上下文的其他项目。这样,您可以实例化彼此的数据上下文并手动调用 OnModelCreating 方法,将当前 DbContext 的 ModelBuilder 作为参数传递。

public class MigrationsDataContext : DbContext
{
    private readonly Dictionary<Type, DbContextOptions> dbCtxOpts;
    private readonly IEnumerable<Type> dbCtxTypes = new[] {
        typeof(CoreDataContext),
        typeof(DbContext1),
        typeof(DbContext2),
    };

    public MigrationsDataContext(DbContextOptions<MigrationsDataContext> options,
        IEnumerable<DbContextOptions> dbCtxOpts)
        :base(options)
    {
        this.dbCtxOpts = dbCtxOpts
            .GroupBy(o => o.ContextType)
            .ToDictionary(g => g.Key, g => g.First());
    }

    public MigrationsDataContext()
    { }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        foreach (var db in dbCtxTypes.Select(t => new { Type = t, Instance = Activator.CreateInstance(t, dbCtxOpts[t]) }))
        {
            var configurator = db.Type.GetMethod(nameof(OnModelCreating), BindingFlags.NonPublic | BindingFlags.Instance);

            configurator.Invoke(db.Instance, new[] { builder });
        }
    }
}

为了从构造函数接收所有 DbContextOptions,您需要将 DbContextOptions<T> 的整个包注册为 DbContextOptions 这是通过在 ConfigureServices 中调用以下方法实现的 Startup.cs:

    public static IServiceCollection AddBundle<T>(this IServiceCollection services)
    {
        var baseType = typeof(T);

        var bundle = services
            .Where(d => baseType.GetTypeInfo().IsAssignableFrom(d.ServiceType))
            .Select(d => d.ServiceType)
            .ToList();

        foreach (var ctxType in bundle)
            services.AddScoped(baseType, s => s.GetService(ctxType));

        return services;
    }

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddEntityFrameworkSqlServer()
            .AddDbContext<CoreDataContext>(ConfigEf)
            .AddDbContext<DbContext1>(ConfigEf)
            .AddDbContext<DbContext2>(ConfigEf)
            .AddDbContext<MigrationsDataContext>(ConfigEf)
            .AddBundle<DbContextOptions>()
            .AddBundle<DbContext>();
...

就是这样。现在您可以这样管理迁移:

移至 Migrations 项目,与 MyWebApp 项目相邻,

`$> dotnet ef --startup-project ../MyWebApp migrations add Initial --context Migrations.MigrationsDataContext`

希望对您有所帮助。