Asp.net core mvc EntityFramework 7(EF7)迁移。DbContext和StartUp项目位于不同的程序集中

Asp.net core mvc EntityFramework 7(EF7)迁移。DbContext和StartUp项目位于不同的程序集中,asp.net-core-mvc,entity-framework-core,Asp.net Core Mvc,Entity Framework Core,我正在尝试将EF7中的迁移与entityframework.commands一起使用。但是,我的DbContext与启动项目位于不同的程序集中(asp.net mvc是一个启动项目,Core.Implementation有一个DbContex) dnx。ef迁移添加MyMigration-c MyContext System.InvalidOperationException:未找到名为“MyContext”的DbContext 我曾尝试使用名称空间指向其他程序集,但它也不起作用。有可能吗?或者

我正在尝试将EF7中的迁移与entityframework.commands一起使用。但是,我的DbContext与启动项目位于不同的程序集中(asp.net mvc是一个启动项目,Core.Implementation有一个DbContex)

dnx。ef迁移添加MyMigration-c MyContext

System.InvalidOperationException:未找到名为“MyContext”的DbContext

我曾尝试使用名称空间指向其他程序集,但它也不起作用。有可能吗?或者,我只需要将我的上下文放在程序集中ef7命令所在的位置?

每个问题,,,&,我们在这方面还有一些工作要做。:-)

编辑

由于1.0.0-rc1-final(可能更早),此解决方案是不必要的

  • 现在,您不需要
    App.DataAccess/Startup.cs
    (如果使用下面的解决方法,只需将其删除即可)
  • 从主项目创建/执行迁移(在本例中
    App.Web
  • 但是,您必须指定包含迁移的项目(
    -p
    paramater):

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

编辑结束

我找到了解决办法

假设您有两个项目:
App.Web
App.DataAccess

您可以将一个非常基本的启动类添加到您的
应用程序中。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
简单启动类(
App.DataAccess\Startup.cs
):

您所要做的就是转到
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

假设我们想将上下文移动到
core1rtemptyTest.DataLayer
project

首先,通过修改子项目的
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/ database update

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

其思想是有一个中心datacontext:
MigrationsDataContext
来处理整个数据库迁移。因此,您可以将此迁移放在一个单独的项目中,该项目仅用于迁移数据库。您只需执行
MigrationsDataContext
即可查看包含所需数据上下文的其他项目。通过这种方式,您可以实例化彼此的datacontext,并将当前DbContext的
ModelBuilder
作为参数手动传递给OnModelCreating方法

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 });
        }
    }
}
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>();
...

希望能有所帮助。

有人知道不需要将实体DbContext与启动项目放在同一程序集中的解决方案吗(我想你们是在研究稳定的解决方案,而不是解决方案)?在执行ef命令时,可以使用一个参数以
MyContext
项目为目标:)@realavaloro没有明显的解决方法。根据,DNX无法加载未引用的程序集,并且从DbContext项目中引用启动项目将导致循环依赖关系:(@bricelam似乎已经解决了提到的问题。这是否意味着在没有@gisek提供的变通方法的情况下,EF7 RC1中现在可以这样做?如果可以,建议的方法是什么?@neodymium看到这个变通方法非常适合我。一旦@bricelam提到的更改实现,我需要重新查看代码但是现在这个很好用。是否可以使用标准的.Net类库(由asp.Net 5 Web应用程序引用)[我需要使用标准类库,因为T4模板在类库包中不起作用]我使用的是“框架”:{“dnxcore50”:{},这能行吗?有什么办法difference@gisek如何使用dotnet而不是dnx实现这一点?@Reft我没有太多时间投入其中。因此,在迁移到ASP Core 1.0.0后,我将迁移文件夹移动到web项目中(仍将模型和DbContext保留在单独的项目中)。然后我运行
dotnet ef migrations add migrationName-c ApplicationDbContext
。虽然可能有更好的方法,但正如我所说,我没有太多时间去探索它。
{
     // 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
D:\path\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ database update
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 });
        }
    }
}
    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;
    }
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddEntityFrameworkSqlServer()
            .AddDbContext<CoreDataContext>(ConfigEf)
            .AddDbContext<DbContext1>(ConfigEf)
            .AddDbContext<DbContext2>(ConfigEf)
            .AddDbContext<MigrationsDataContext>(ConfigEf)
            .AddBundle<DbContextOptions>()
            .AddBundle<DbContext>();
...
`$> dotnet ef --startup-project ../MyWebApp migrations add Initial --context Migrations.MigrationsDataContext`