2012-04-18 131 views
1

當您使用存儲庫模式開發ASP.NET應用程序時,請爲每種方法創建一個帶有使用塊的新實體容器實例(上下文),或者你創建了容器的類級別/私有實例供任何存儲庫方法使用,直到存儲庫本身被丟棄爲止?除了我在下面注意到的,有什麼優點/缺點?有沒有一種方法可以結合我沒有看到的每種方法的優點?您的存儲庫是否實現了IDisposable,允許您爲repo實例創建塊?ASP.NET MVC - 使用實體框架的存儲庫模式

多個容器(相對於單個)

優點:

  • 被防止連接自動關閉/設置(將在使用塊的末尾被關閉)。
  • 有助於強制您將特定視圖/視圖模型所需的內容拉入內存中,並在較少的往返行程中(對於嘗試延遲加載的任何內容,您將獲得連接錯誤)。

缺點:

  • 控制器內的子實體的訪問/查看僅限於你叫什麼包括()
  • 對於像儀表板指數,顯示信息頁面許多聚集表(許多不同的庫方法調用),我們將增加創建和處理許多實體容器的開銷。
+0

關閉主題?真的嗎?我可以看到關閉不是建設性的(雖然我也會反對這一點,但肯定比「off topic」更準確) – 2012-04-18 17:51:02

回答

2

如果您實例存儲庫中的您的上下文,那麼你應該總是做在本地,並且在using語句包裹。

如果您使用依賴注入注入的背景下,然後讓你的DI容器處理調用dispose上下文當請求完成。

不要直接實例化您的上下文作爲類成員,因爲這不會在發生垃圾回收之前處理上下文資源。如果你這樣做,那麼你將需要實現IDipsosable來處理上下文,並確保正在使用您的存儲庫的任何東西都能正確處理您的存儲庫。

+0

你只需要自己處置庫類(並且將上下文置於repo的Dispose方法中),那麼你可以安全地使用該類作爲成員的上下文。他在他的問題中已經表明了這一點:「*您的存儲庫是否實現了IDisposable,允許您爲回購實例創建塊?*」 – Slauma 2012-04-18 18:23:52

+0

@Mystere偉大的迴應 - 我很驚訝我從未想過爲此目的使用DI儘管它似乎完全適合它。簡單的解決方案,謝謝! – Keith 2012-04-18 18:57:57

0

我個人將我的上下文放在我的存儲庫中的類級別上。我這樣做的主要原因是因爲存儲庫模式的一個明顯優勢是我可以輕鬆地交換存儲庫並利用不同的後端。請記住 - 存儲庫模式的目的是爲您提供一個爲某些客戶端提供備份數據的界面。如果您切換數據源,或者只是想通過依賴注入提供新的數據源,那麼如果您在每個方法級別執行此操作,則會創建更難的問題。

微軟的MSDN網站有很好的信息repository pattern。希望這有助於澄清一些事情。

+0

不幸的是,這意味着Dispose不會在您的上下文中調用,這意味着您可以打開數據庫連接(加上使用中的大量內存),直到垃圾收集器開始清理它。這就是爲什麼你應該總是將你的上下文封裝在一個使用塊中,以便儘快處理它們。 – 2012-04-18 17:46:42

+0

@MystereMan - 好點,但你如何解決我在我的文章中提出的另一個問題? (現在你有責任爲每一種添加重要的開發/代碼開銷的方法進行設置。)我個人從來沒有見過這樣做。 (並不意味着我是正確的,但它使我更加懷疑。) – JasCav 2012-04-18 17:50:31

+0

我不明白你的第二個問題。如果使用依賴注入,則讓DI容器處理調用dispose。如果他們使用DI與實例化他們自己的對象,則類的設計方式會有所不同。切換可能更多工作,但這就是爲什麼你應該從DI開始。 – 2012-04-18 17:54:06

0

我不同意所有四點:

被自動關閉/設置防止連接(將在使用塊的結尾關閉 )。

在我看來,如果在方法級別,存儲庫實例級別或請求級別上處理上下文,則無關緊要。 (你當然在單個請求結束時處理上下文 - 通過將存儲庫方法包裝在using聲明中或通過在存儲庫類上實現IDisposable(如您所建議的)並將存儲庫實例包裝在using語句或通過在控制器構造函數中實例化存儲庫並將其置於控制器類的重寫中 - 或者在請求開始時通過實例化上下文並在請求結束時進行處理(某些依賴注入容器將有助於做這個工作)。)爲什麼上下文應該「自動處理」?在桌面應用程序中,每個窗口/視圖都有一個可能會打開幾個小時的上下文是可能的和常見的。

有助於迫使你只能拉入內存,你需要什麼樣的 特定視圖/視圖模型,並在更短的往返(你會得到任何你試圖延遲加載一個 連接錯誤)。

老實說,我會通過完全禁用延遲加載來強制執行此操作。我沒有看到在客戶端與服務器斷開連接的Web應用程序中進行延遲加載的好處。在你的控制器動作中,你總是知道你需要加載什麼,並且可以使用急切或顯式加載。爲避免內存開銷並提高性能,您可以始終禁用GET請求的更改跟蹤,因爲EF無論如何都無法跟蹤客戶端網頁上的更改。

控制器內的子實體的訪問/查看僅限於什麼 你調用包括()

這是相當具有優勢不是一個劣勢,因爲你沒有的unwished驚喜延遲加載。如果您需要在控制器動作後填充子實體,這取決於一些條件,你可以通過額外的儲存庫的方法(LoadNavigationProperty或東西)具有相同或甚至一個新的上下文加載它們。

對於像儀表板指數顯示,從 許多表(很多不同的版本庫的方法調用)收集的信息的網頁,我們將添加 開銷創建和處理許多實體容器。

創建上下文 - 我不認爲我們正在談論數百或數千個實例 - 是一種便宜的操作。我認爲這是一個非常理論化的開銷,在實踐中沒有發揮作用。

我使用這兩種方法,你在web應用中提到,也是第三個選項,即創建每個請求一個上下文並注入同樣的情況下到每一個存儲庫/服務,我需要在一個控制器動作。他們三人都爲我工作。

當然,如果你使用,你必須要小心做同一個工作單位的各項工作,以避免安裝實體多個上下文,這將導致衆所周知的例外多個上下文。避免這種情況通常不是問題,但需要更多的關注,特別是在處理POST請求時。

我最近使用每個請求的上下文,因爲它更容易,我只是沒有看到有非常狹窄的上下文的好處,我沒有理由在整個請求處理中使用多個工作單元。如果我需要多個上下文 - 無論出於何種原因 - 我總是可以創建專門的方法來處理它們自己的上下文,而不是請求的「默認上下文」。

+0

我們在這裏討論的是一個web應用程序,而不是桌面應用程序。桌面應用程序通常具有大量資源,並且可以將環境打開幾個小時。 Web應用程序往往需要儘快釋放資源,因爲您不知道服務器將承受多少負載。 Web應用程序與桌面應用程序有着根本不同的資源管理需求。 – 2012-04-18 17:48:39

+0

@MystereMan:你是說在一個請求被完全處理之前,一個web進程可能釋放用在請求中的資源*?我沒有說要讓一個上下文(或多個上下文)在比單個請求更長的時間內打開。我不明白你的批評意見。 – Slauma 2012-04-18 17:58:08

+0

如果將上下文放在類級別上,則在請求完成時不會處理上下文。即使請求不再使用它,它仍將消耗資源和可能的連接,直到垃圾收集發生。如果你使用DI來注入上下文,那麼你的DI容器可以在請求結束時調用dispose,或者如果你直接實例化對象,那麼你需要將它包裝在using語句中,以便在完成後立即釋放資源它。 – 2012-04-18 17:59:47