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.Web
和 App.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`
希望对您有所帮助。
我正在尝试通过 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.Web
和 App.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`
希望对您有所帮助。