2012-09-14 63 views
2

我建立使用實體框架代碼首先與mvc4 Web應用程序的方式分層的應用,主要是分離的DataServicesWeb實體框架:Code First。共享和實例上下文

從我的網站我這樣做:

public void Foo() { 
    EntityService _svc = new EntityService(); 
    Entity = _svc.FindById(1); 
} 

服務的方法是這樣的:

private readonly MyContext _ctx = new MyContext(); 

public Entity FindById(long id) { 
    return _ctx.Entities.SingleOrDefault(q => q.EntityId == id); 
} 

問題是,當我需要使用一個以上的服務,因爲每個服務將創建它是自己的上下文。

試圖解決這個我做了這樣的事情:

public class MyContext : DbContext { 
    private static MyContext _ctx; 

    public MyContext() : base("name=myConnectionString") { } 

    public static MyContext GetSharedInstance() { 
     return GetSharedInstance(false); 
    } 

    public static MyContext GetSharedInstance(bool renew) { 
     if(_ctx == null || renew) 
      _ctx = new MyContext(); 

     return _ctx; 
    } 
} 

改變了我的服務內容如下:

public class EntityService 
{ 
    private readonly MyContext _ctx; 

    public bool SharedContext { get; private set; } 

    public EntityService() 
     : this(false) { } 

    public EntityService(bool sharedContext) 
     : this(sharedContext, false) { } 

    public EntityService(bool sharedContext, bool renew) 
    { 
     SharedContext = sharedContext; 

     if (SharedContext) 
      _ctx = MyContext.GetInstance(renew); 
     else 
      _ctx = new MyContext(); 
    } 
} 

現在,如果我想分享我的上下文的實例,我做這樣的事情:

EntityService _entitySvc = new EntityService(true, true); 
AnotherEntityService _anotherEntitySvc = new AnotherEntityService(true); 

這是,至少,這是一個體面的方式來克服呢?我會感謝提供的任何幫助。謝謝。

回答

10

永遠不要永遠永遠永遠永遠永遠永遠永遠... ...我提到過的?我是認真的。永遠不要創建一個靜態數據上下文。永遠不能。真。我能再強調一下嗎?決不。甚至不要去想它。思考它會給你腦癌。

這是在依賴注入真正的亮點的情況之一。通過依賴注入,您可以管理數據上下文的生命週期,並使它們在請求的整個生命週期內運行,而不是應用程序池的生命週期,如靜態一樣。

詳細說明共享上下文爲什麼不好。不僅上下文在你的類中共享,而且在線程和請求之間共享。這意味着同時使用該網站的兩個用戶會在所有其他數據上下文中跺腳,導致各種問題。數據上下文不是線程安全的,它們並不安全。

如果你想分享與多個對象的數據上下文,那麼你需要將它傳遞給這些對象,無論是作爲一個方法調用的一部分,或作爲一個構造函數參數。

我強烈建議通過依賴注入這樣做,但是。

+0

+1爲DI提,每個請求是要走的路。 – Maess

+0

好的,點了。你能否給我提供一些關於如何通過DI實現這一點的指導,也許我可以用一個簡短的例子來改變我的解決方案?謝謝。 – Esteban

+0

@Esteban - 不幸的是,有很多不同種類的依賴注入容器,在你到達那裏之前,你需要更多地瞭解DI。所以很難舉一個例子,因爲你選擇哪個DI容器會影響事物。 –

1

我偶然在此尋找別的東西,而且我最近建立了實體框架的存儲庫模式。它旨在封裝框架,同時讓自己的存儲庫模式發光。你會想要遵循Mystere Man的建議。以下是我建議你接近它的一個粗略示例。

public class MyContext: DbContext, IUnitOfWork 
{ 
    public IDbSet<Note> Notes { get; set; } 
    public IDbSet<DomainType> DomainTypes { get; set; } 
    public IDbSet<DomainValue> DomainValues { get; set; } 
    public IDbSet<Party> Parties { get; set; } 

    public MyContext() :base() 
    { 
     Configuration.LazyLoadingEnabled = false; 
     Configuration.ProxyCreationEnabled = false; 
    } 
} 

正如你所看到的,是的DbContext的IUnitOfWork,它只是有它SaveChanges方法。這是你傳入你的倉庫的內容。

public abstract class BaseEfRepository<T, TU> : IRepository<T> 
    where T : class 
    where TU : IUnitOfWork 
{ 
    ... 
    virtual public T GetSingle(Expression<Func<T, bool>> whereCondition) 
    { 
     Log.DebugFormat("Called GetSingle<{0}>()...", typeof(T)); 
     return MyEntitySet.Where(whereCondition).FirstOrDefault(); 
    } [etc...] 

} 

這將有大部分的基本的倉庫風格的收集訪問者和你想要什麼封裝的。UnitOfWork被傳入存儲庫,因此您可以在同一個事務中擁有任意數量的存儲庫。

public class NoteRepository: BaseEfRepository<Note, MyContext> 
{ 
    public NoteRepository(MyContext uow) : base(uow) 
    { 
     MyEntitySet = uow.Notes; 
    } 
    public Note GetSingleWithParties(Expression<Func<Note, bool>> whereCondition) 
    { 
     return [... whatever ...] 
    } 

} 

我希望這證明有用。

相關問題