2016-02-14 41 views
1

我對我的MVVM應用程序(以前稱爲WinRT,現在針對UWP)關於數據訪問的體系結構非常困惑。我很不確定如何在UI中傳播更改以及將數據訪問權限放在哪裏。MVVM體系結構:一種模型 - 幾種視圖模型+數據訪問的地方

這裏的基本架構:

  1. 模型層:包含的型號只有自動屬性(引用了其他車型沒有導航性能,只是IDS,所以他們基本上只是數據庫的表示)。他們不實施INotifyPropertyChanged。
  2. 數據訪問層:使用sqlite-net將模型存儲在數據庫中的存儲庫。它暴露了基本的CRUD操作。它從模型層返回並接受模型。
  3. 的ViewModels
    • 的ViewModels爲模特:他們環繞模式和揭露性質。有時我雙向綁定控件的內容(例如TextBoxes)到屬性。然後設置者訪問數據層以堅持這一改變。
    • PageViewModal for Views:它們包含上面的ViewModels和Commands。許多命令已經變得非常長,因爲它們執行數據訪問,執行特定於域的邏輯並更新PageViewModels屬性。
  4. 視圖(頁面):它們結合PageViewModels並通過的DataTemplate到的ViewModels爲模特。有時候會有雙向數據綁定,有時我會使用命令。

我現在有幾個問題與此架構:

問題1:一個模型可以在屏幕上幾個宮殿來表示。例如,顯示一個類型的所有可用實體列表的主 - 細節視圖。用戶可以選擇其中的一個,並在詳細視圖中顯示其內容。如果用戶現在在詳細視圖中更改屬性(例如,模型的名稱),則更改應立即反映在主列表中。這樣做的最好方法是什麼?

  1. 已有一個ViewModel的型號爲?我不認爲這很有道理,因爲主列表只需要很少的邏輯,而詳細視圖更多。
  2. 模型實現INotifyPropertyChanged並因此將更改傳播到ViewModels?我遇到的問題是數據層目前不能保證它在一個模型ID上對兩個讀取操作返回的對象是相同的 - 它們只包含從數據庫中讀取的數據,並在讀取時新創建(我認爲這就是sqlite-net的工作方式)。我也不確定如何避免由於ViewModels中的所有PropertyChanged事件訂閱而發生內存泄漏。我應該實現IDisposable並讓PageViewModel調用其子項的Dispose()方法嗎?
  3. 我目前在我的數據訪問層上有一個DataChanged事件。只要發生創建,更新或刪除操作,就會調用它。可以同時顯示的每個ViewModel監聽此事件,檢查已更改的模型是否爲ViewModel的模型,然後更新其自己的屬性。我再次遇到了內存泄漏的問題,並且這種情況變得緩慢,因爲太多的ViewModel必須檢查更改是否真的適合他們。
  4. 另一種方式?

問題2:我也不確定我訪問數據的地方是否真的很好選擇。 PageViewModel已經變得非常複雜,基本上都做了。所有ViewModel都需要我的架構知識數據層。

我一直在考慮使用sqlite-net來取消數據訪問,並使用Entity Framework 7來代替。這是否可以解決上述問題,也就是說,當我使用相同的上下文時,它是否可以保證一個模型的對象標識?我也認爲這會簡化ViewModels,因爲我很少需要讀取操作,因爲這是通過導航屬性完成的。

我也一直在想,在MVVM應用程序中是否有兩種方式的數據綁定是好主意,因爲它需要屬性設置器調用數據訪問層來保持更改。只做單向綁定並通過命令堅持所有更改會更好嗎?

如果有人能評論我的架構並提出改進建議或指出關注我的問題的MVVM體系結構上的優秀文章,我將非常高興。

回答

3
  1. 該模型有一個ViewModel?我不認爲這很有道理,因爲主列表只需要很少的邏輯,而詳細視圖更多。

ViewModel不依賴於模型。 ViewModel使用該模型來滿足視圖的需求。 ViewModel是視圖的單一聯繫人,因此ViewModel必須提供任何視圖。所以它可以是單個模型/多個模型。但是,您可以將單個ViewModel分解爲多個子ViewModel,以使邏輯更加簡單。它的詳細信息窗格可以使用其自己的視圖模型分成用戶控件。您的母版頁將只擁有將承載此控件的窗口,MasterViewmodel將把責任推送到子ViewModel。

  • 讓模型執行INotifyPropertyChanged並因此傳播換到的ViewModels?我遇到的問題是, 數據層當前不能保證它返回的對象 對於一個模型ID上的兩個讀取操作是相同的 - 它們只是 包含從數據庫讀取的數據,並且是在創建時 它們被讀取(我認爲這是sqlite-net的工作方式)。我也不是 真的很確定如何避免發生內存泄漏,因爲ViewModels中的所有 PropertyChanged事件訂閱。我應該 實現IDisposable並讓PageViewModel調用其子組件 Dispose()方法嗎?
  • 的危險是不使用INotifyPropertyChanged,但你說得對與subcribing和取消它。無論何時需要訂閱任何活動 - 不僅需要INotifyPropertyChanged,還需要使用IDisposable取消訂閱自己及其子ViewModels。我不清楚你描述的數據層,但如果它發佈任何修改的屬性更改事件我沒有看到使用INotifyPropertyChanged的任何問題。

    3.我目前在我的數據訪問層上有一個DataChanged事件。只要發生創建,更新或刪除操作,就會調用它。可以同時顯示的每個 ViewModel監聽此事件, 檢查更改後的模型是否爲ViewModel for的版本,然後更新其自身的屬性。我再次遇到了內存泄漏的問題,並且這種情況變得緩慢,因爲太多的ViewModel不得不通過 來檢查更改是否真的適用於他們。

    正如我剛纔所說,如果你處理訂閱/退訂正確適用於所有型號,你不用擔心INotifyPropertyChanged的性能問題。但是可能會增加這個問題的是你爲了請求數據而對數據庫進行的調用次數。你有沒有考慮過使用異步...等待數據訪問層,這將不會阻止用戶界面的任何更新發生。即使數據更新速度慢,數據調用阻止的反應式UI也是更好的選擇。

    因此,請嘗試添加抽象到DAL層上的數據訪問服務,並提供異步訪問數據的方法。也看看Mediator Pattern。這可能會有幫助。

    我也不確定我訪問數據的地方是否真的很好 選擇。 PageViewModels已經變得非常複雜,並且基本上都做了所有事情。所有ViewModel都需要了解我的體系結構的數據層的 。

    兩個主要問題,我看,

    1. 如果你覺得PageViewModel過於龐大分解成可管理大小的子視圖模型。它非常主觀,所以你必須嘗試用自己的視圖模型來查看所有的部分可以分解成它自己的組件/用戶控件。
    2. 當你說ViewModels需要知道數據層,我希望你的意思是他們依賴於一個管理DAL層服務的接口,並且不能直接訪問帶有CRUD方法的類。如果不嘗試添加一個抽象層,那你實際上在你的視圖模型中做了什麼。這將處理DAL CRUD操作。

    我一直在想報廢使用SQLite網的數據訪問和使用 實體框架7代替。

    不要試圖用沒有確鑿證據的EF代替sqlite-net。您需要先測試應用程序的性能,然後才能嘗試進行如此大的更改。如果問題在於你的代碼而不是你正在使用的組件。首先嚐試解決上述問題,然後您可以通過接口隔離DAL層,並在需要時替換它。

    我也一直在想有兩個方式綁定是好主意 在所有在MVVM應用程序,因爲它需要的屬性setter 調用數據訪問層堅持的變化。 更好嗎只做單向綁定並通過命令持續所有更改?

    如果您每次對字段/每個關鍵筆劃進行更改都直接調用數據庫,那麼這是一個問題。然後,您應該擁有數據模型的副本,並僅在您單擊保存按鈕時才保留更改。

    +0

    我想我要添加一個數據服務層,目前所有ViewModel訪問DAL的接口。我的數據訪問已經是異步的,但我正在考慮將其設爲**同步**,因爲我通常連續進行數百次讀取操作。 (更少但更復雜的需要直接暴露sqlite-net功能。)這會降低性能,因爲每個小請求都有創建任務的開銷(這是sqlite-net的做法),並且也阻止了使用的交易。因此,訪問DAL將是同步的,但新的數據服務層將是異步的。 – SebastianR

    +0

    並感謝您的長時間回答,CarbineCoder!這已經幫了我不少。 – SebastianR

    +0

    乾杯...我很高興這很有幫助。除非你做錯了,否則你不必擔心任務創建的開銷。數據服務層的想法是好的,需要的。除非您證明異步導致問題不要刪除它。無需證明,您可能會通過進行優化前的優化來損害系統。我建議不要這樣做,除非你可以模擬你的方法並測量差異。 – CarbineCoder

    相關問題