2010-10-18 92 views
30

我第一次使用Entity框架,想知道我是否在最佳實踐中使用。業務邏輯中的實體框架最佳實踐?

我在業務邏輯中創建了一個獨立的類,它將處理實體上下文。我遇到的問題是,在我看到的所有視頻中,他們通常會將使用語句中的上下文封裝起來以確保其關閉,但顯然,我無法在業務邏輯中執行此操作,因爲在我實際上可以實際上關閉上下文用它?

那麼這就好了我在做什麼?一對夫婦的例子:

public IEnumerable<Article> GetLatestArticles(bool Authorised) 
    { 
     var ctx = new ArticleNetEntities(); 
     return ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate); 
    } 

    public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised) 
    { 
     var ctx = new ArticleNetEntities(); 
     return ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate); 
    } 

我只是想確保我沒有建立這回事時,很多人用它來死的東西嗎?

回答

62

這確實取決於如何公開您的存儲庫/數據存儲。

不確定你的意思是「上下文將被關閉,因此我不能做業務邏輯」。在裏面使用你的商業邏輯。或者,如果您的業務邏輯處於不同的班級,那麼讓我們繼續。 :)

一些人返回他們的庫藏品的混凝土,在這種情況下,你可以用在using語句上下文:

public class ArticleRepository 
{ 
    public List<Article> GetArticles() 
    { 
     List<Article> articles = null; 

     using (var db = new ArticleNetEntities()) 
     { 
     articles = db.Articles.Where(something).Take(some).ToList(); 
     } 
    } 
} 

的這種優勢在滿足使用連接的很好的做法 - 遲開你可以,並儘早關閉。

您可以將所有業務邏輯封裝在using語句中。

缺點 - 您的存儲庫意識到業務邏輯,這是我個人不喜歡的,並且最終針對每種特定方案都會有不同的方法。

第二個選項 - 新增一個上下文作爲存儲庫的一部分,並使其實現IDisposable。

public class ArticleRepository : IDisposable 
{ 
    ArticleNetEntities db; 

    public ArticleRepository() 
    { 
     db = new ArticleNetEntities(); 
    } 

    public List<Article> GetArticles() 
    { 
     List<Article> articles = null; 
     db.Articles.Where(something).Take(some).ToList(); 
    } 

    public void Dispose() 
    { 
     db.Dispose(); 
    } 

} 

然後:

using (var repository = new ArticleRepository()) 
{ 
    var articles = repository.GetArticles(); 
} 

還是第三個選項(我的最愛),使用依賴注入。從你的版本庫分離的所有方面工作,並讓DI容器處理處置的資源:

public class ArticleRepository 
{ 
    private IObjectContext _ctx; 

    public ArticleRepository(IObjectContext ctx) 
    { 
     _ctx = ctx; 
    } 

    public IQueryable<Article> Find() 
    { 
     return _ctx.Articles; 
    } 
} 

您所選擇的DI容器將注入混凝土的ObjectContext到存儲庫中的實例,與配置的壽命(辛格爾頓, HttpContext,ThreadLocal等),並基於該配置對其進行處置。

我已經設置好每個HTTP請求都會得到一個新的上下文。請求完成後,我的DI容器將自動處理上下文。

我還在這裏使用工作單元模式來允許多個存儲庫使用一個對象上下文。

您可能也注意到我更喜歡從我的Repository中返回IQueryable(而不是具體的List)。更強大(但風險很大,如果你不瞭解其含義)。我的服務層在IQueryable上執行業務邏輯,然後將具體集合返回給UI。

這是我迄今爲止最強大的選擇,因爲它允許一個簡單的操作,工作單元管理上下文,服務層管理業務邏輯,DI容器處理資源/對象。

讓我知道你是否想要更多的信息 - 因爲它有很多,甚至超過這個令人驚訝的長答案。 :)

+0

不用擔心。 :)看看我的一些其他問題/答案 - 最近我一直在處理這個問題。我並不打算這麼長時間,但我想我已經走了 - 畢竟,這是一個相當複雜的話題。 :) – RPM1984 2010-10-18 21:18:18

+2

您能否詳細解釋一下您如何使用工作單元模式?我認爲EF ObjectContext實際上是一個UoW。 – Santhos 2013-10-07 12:54:31

+4

我想知道的是這個最終版本增加了什麼?它看起來像是在實體框架之外的一個額外的抽象,因爲實體框架本身已經實現了工作單元和存儲庫。爲什麼使用這個存儲庫類而不是實體datacontext本身? – Tobberoth 2014-10-13 06:47:27

3

我將ctx作爲每個類中的私有變量,然後每次創建一個新的實例,然後在完成時進行處理。

public class ArticleService 
{ 
    private ArticleEntities _ctx; 

    public ArticleService() 
    { 
     _ctx = new ArticleEntities(); 
    } 

    public IEnumerable<Article> GetLatestArticles(bool Authorised) 
    {    
     return _ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate); 
    } 

    public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised) 
    {   
     return _ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate); 
    } 

    public void Dispose() 
    { 
     _ctx.Dispose(); 
     _ctx = null; 
    } 

} 

然後當調用這個。

ArticleService articleService = new ArticleService(); 
IEnumerable<Article> article = articleService.GetLatestArticles(true); 
articleService.Dispose(); // killing the connection 

這種方式,您還可以在同一範圍內添加/更新其他對象,並調用保存方法,從而節省了通過實體數據庫進行任何更改。

+1

感謝您的示例:)讚賞 – leen3o 2010-10-18 12:48:28

+0

謝謝你的回答! – killexe 2016-11-03 10:23:38

+0

@killexe最受歡迎。 – 2016-11-03 10:38:44

1

您還可以做的是將您的上下文存儲在更高級別。

例如,你可以有一個靜態類存儲當前情境:

class ContextManager 
{ 
    [ThreadStatic] 
    public static ArticleEntities CurrentContext; 
} 

然後,外面的某個地方,你做這樣的事情:

using (ContextManager.CurrentContext = new ArticleEntities()) 
{ 
    IEnumerable<Article> article = articleService.GetLatestArticles(true); 
} 

然後,GetLastestArticles裏面,您只需要使用相同的ContextManager.CurrentContext。

當然,這只是基本的想法。通過使用服務提供商,IoC等,您可以使這更加可行。

3

以我的經驗,這段代碼不好,因爲你失去了通過導航屬性導航關係的能力。

public List<Articles> getArticles(){ 
    using (var db = new ArticleNetEntities()) 
    { 
     articles = db.Articles.Where(something).ToList(); 
    } 
} 

使用這種方法,因爲a.Members總是空,你不能使用下面的代碼(DB環境是密切和無法自動獲取數據)。

var articles = Data.getArticles(); 
    foreach(var a in articles) { 
     if(a.Members.any(p=>p.Name=="miki")) { 
      ... 
     } 
     else { 
      ... 
     } 
    } 
} 

只使用一個全球數據庫方面是一個糟糕的主意,因爲你必須使用一個刪除變化點應用程序的喲做到這一點,但不保存更改並關閉窗口函數

var article= globalcontext.getArticleByID(10); 
article.Approved=true; 

然後在應用程序的另一點,你做一些操作,節省

//..... something 
globalcontext.saveChanges(); 

在這種情況下,先前文章批准的屬性設置爲由實體框架修改。當你保存,批准設置爲真!

最適合我的方法是用每類1個上下文 你可以通過上下文,如果你需要

class EditArticle { 

    private DbEntities de; 
    private currentAricle; 

    public EditArticle() { 
     de = new DbEntities; //inizialize on new istance 
    } 

    loadArticleToEdit(Articele a){ 
     // a is from another context 
     currentArticle= de.Article.Single(p=>p.IdArticle==a.IdArticle){ 
    } 

    private saveChanges(){ 
     ... 
     pe.saveChanges(); 
    } 
} 
0

您可以通過創建一個通用的存儲庫類開始從數據訪問層準備實體框架的另一個外部方法所有必需的實體框架功能。

    :然後你就可以在業務層(封裝)

    下面是用於這種做法

    技術,我已經在數據業務使用實體框架的最佳實踐,並且UI層中使用它

  1. 應用SOLID architecture principles
  2. 使用資源庫設計模式
  3. 只有一個班去(你會發現它準備好)