Asp.net core mvc EntityFramework 7(EF7)迁移。DbContext和StartUp项目位于不同的程序集中
我正在尝试将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(可能更早),此解决方案是不必要的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 我曾尝试使用名称空间指向其他程序集,但它也不起作用。有可能吗?或者
- 现在,您不需要
(如果使用下面的解决方法,只需将其删除即可)App.DataAccess/Startup.cs
- 从主项目创建/执行迁移(在本例中
)App.Web
- 但是,您必须指定包含迁移的项目(
paramater):-p
如果有多个数据库上下文,还必须指定要使用的数据库上下文(
-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`