2016-08-12 85 views
2

我有一個簡單DbContext看起來像:的DbContext和範圍依賴

public class MyDbContext : DbContext 
{ 
    private readonly IUserContext _userContext; 

    public MyDbContext(IUserContext userContext) : base("DefaultConnectionString") 
    { 
     _userContext = userContext; 

     Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>()); 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // ... Here I need to creates some filters using the IUserContext dependency 

     base.OnModelCreating(modelBuilder); 
    } 

} 

DbContext使用Func<T>工廠,using the guidelines in the Simple Injector documentation有線:container.RegisterFuncFactory<DbContext, MyDbContext>(Lifestyle.Scoped);

public static void RegisterFuncFactory<TService, TImpl>(
    this Container container, Lifestyle lifestyle = null) 
    where TService : class 
    where TImpl : class, TService 
{ 
    lifestyle = lifestyle ?? Lifestyle.Transient; 
    var producer = lifestyle.CreateProducer<TService, TImpl>(container); 
    container.RegisterSingleton<Func<TService>>(producer.GetInstance); 
} 

但apperently,這種簡單的情況下是不可能的DbContext因爲此消息:

目標上下文'MyDbContext'不可構造。添加一個默認的 構造函數或提供IDbContextFactory的實現。

我真的不喜歡的IDbContextFactory的想法,所以唯一的解決辦法,我能想出是去除依賴於MyDbContext,將其設置爲一個屬性,修改RegisterFuncFactory方法和手動初始化的背景:

internal static void RegisterFuncFactory<TService, TImpl>(this Container container, Func<TImpl> instanceProducer, Lifestyle lifestyle = null) where TService : class where TImpl : class, TService 
{ 
    lifestyle = lifestyle ?? Lifestyle.Transient; 
    var producer = lifestyle.CreateProducer<TService>(instanceProducer, container); 
    container.Register<Func<TService>>(() => producer.GetInstance, Lifestyle.Singleton); 
} 

container.RegisterFuncFactory<DbContext, MyDbContext>(() => new MyDbContext 
{ 
    UserContext = container.GetInstance<IUserContext>() 
}, Lifestyle.Scoped); 

儘管它不夠優雅,但是還有其他更好的方法來滿足我的需求嗎?我喜歡明確依賴上下文,但似乎不可能。

UPDATE

錯誤是來自:

'System.Data.Entity.Migrations.Infrastructure.MigrationsException' 發生在EntityFramework.dll但在用戶代碼

沒有處理

在此代碼查詢方法這裏的return語句:

internal sealed class EntityFrameworkRepository<TEntity> : IEntityWriter<TEntity>, IEntityReader<TEntity> where TEntity : Entity 
{ 
    private readonly Func<DbContext> _contextProvider; 

    public EntityFrameworkRepository(Func<DbContext> contextProvider) 
    { 
     _contextProvider = contextProvider; 
    } 

    public IQueryable<TEntity> Query() 
    { 
     var context = _contextProvider(); 
     return context.Set<TEntity>().AsNoTracking(); 
    } 

    // Methods removed for brevity 

} 
+0

誰給你這個消息:

public class MyDbContext : DbContext { private readonly IUserContext _userContext; // For migrations public MyDbContext() : base("DefaultConnectionString") { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>()); } // For applications public MyDbContext(IUserContext userContext) : base("DefaultConnectionString") { _userContext = userContext; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // ... Code removed for brevity base.OnModelCreating(modelBuilder); } } 

這是然後在根組成像有線? EF遷移? – Steven

+0

是的,錯誤來自EntityFramework中發生的'System.Data.Entity.Migrations.Infrastructure.MigrationsException'。dll,但沒有在用戶代碼中處理返回statemenet在這裏:var context = _contextProvider();返回context.Set ().AsNoTracking();' – janhartmann

+0

@janhartmann什麼是實體(約束)?我認爲你也應該指定一個'class'約束,因爲現在'TEntity'可能是一個不允許的接口 –

回答

2

添加第二個(默認)構造函數。這樣,EF遷移可以在從命令行運行時使用此構造函數,而您可以讓您的應用程序使用第二個構造函數。

當您添加第二個構造函數時,您在DbContext上鬆動了簡單噴射器的自動佈線功能,但這不應該是一個問題;你可以簡單地連接你的上下文,如下所示:

IUserContext userContext = new AspNetUserContext(); 

container.RegisterSingleton<IUserContext>(userContext); 

var contextProducer = Lifestyle.Scoped.CreateProducer<DbContext>(
    () => new MyDbContext(userContext), 
    container); 

container.RegisterSingleton<Func<DbContext>>(contextProducer.GetInstance); 
+0

謝謝Steven,要試試這個。我不得不將單身人士註冊編號改爲:'container.RegisterSingleton >(()=> contextProducer.GetInstance);' – janhartmann

+0

像魅力一樣工作!我會將您的答案標記爲解決方案,我會爲其他人發佈完整解決方案的答案(或者這是不允許的?)。 – janhartmann

+0

@janhartmann:我認爲發佈完整的解決方案是一個很好的做法。更多的人應該這樣做。 – Steven

0

這個答案只是爲了向更多的用戶展示我結束了什麼。 @Steven的答案是正確的答案。

爲了能夠在支持遷移時將相關性注入到DbContext中,我們必須使用兩個構造函數。一個用於遷移,一個用於應用程序。

public static void RegisterEntityFramework<TContext>(this Container container, Func<TContext> context) where TContext : DbContext 
{ 
    if (container == null) throw new ArgumentNullException(nameof(container)); 

    var contextProducer = Lifestyle.Scoped.CreateProducer<DbContext>(context, container); 
    container.RegisterSingleton<Func<DbContext>>(() => contextProducer.GetInstance); 
} 

var userContext = new AspNetHttpUserContext(); 
var container = new Container(); 
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(); 
container.RegisterSingleton<IUserContext>(userContext); 
container.RegisterEntityFramework(() => new WayFinderDbContext(userContext)); 
container.Verify();