MVVM 架构:一个模型 - 多个视图模型 + 数据访问的地方
MVVM architecture: one model - several view models + place for data access
我对涉及数据访问的 MVVM 应用程序(以前称为 WinRT,现在面向 UWP)的体系结构感到很困惑。我非常不确定如何在 UI 中传播更改以及在何处访问数据层。
基本架构如下:
- 模型层: 包含只有自动属性的模型(没有引用其他模型的导航属性,只有 ID;所以它们基本上只是数据库的表示)。他们没有实现 INotifyPropertyChanged。
- 数据访问层:一个使用sqlite-net在数据库中存储模型的存储库。它公开了基本的 CRUD 操作。它 returns 并从模型层接受模型。
- 视图模型:
- 模型的 ViewModels:它们环绕模型并公开属性。有时我将控件(例如文本框)的内容双向绑定到属性。 setter 然后访问数据层以保留此更改。
- View 的 PageViewModels:它们包含上面的 ViewModels 和命令。许多命令在进行数据访问、执行域特定逻辑和更新 PageViewModels 属性时变得很长。
- 视图(页面):它们绑定到 PageViewModel,并通过 DataTemplate 绑定到模型的 ViewModel。有时有双向数据绑定,有时我使用命令。
我现在对这个架构有几个问题:
问题一:一个模型可以出现在几个宫殿的屏幕上。例如,显示一个类型的所有可用实体列表的主从视图。用户可以 select 其中之一,其内容显示在详细信息视图中。如果用户现在在详细视图中更改 属性(例如模型名称),则更改应立即反映在主列表中。这样做的最佳方法是什么?
- 有模型的一个 ViewModel?我认为这没有多大意义,因为主列表只需要很少的逻辑,而详细视图则需要更多。
- 让 模型实现 INotifyPropertyChanged 从而将更改传播到 ViewModels?我遇到的问题是,数据层目前不保证它 returns 对一个模型 id 进行两次读取操作的对象是相同的——它们只包含从数据库读取的数据并且是新创建的当它们被阅读时(我认为这就是 sqlite-net 的工作方式)。我也不太确定如何避免由于来自 ViewModel 的所有 PropertyChanged 事件订阅而发生内存泄漏。我是否应该实施 IDisposable 并让 PageViewModel 调用其子项的 Dispose() 方法?
- 我目前在我的数据访问层 上有一个 DataChanged 事件。只要发生创建、更新或删除操作,就会调用它。每个可以同时显示的 ViewModel 都会监听这个事件,检查更改的模型是否是它的 ViewModel 对应的模型,然后更新自己的属性。我再次遇到内存泄漏的问题,这变得很慢,因为太多的 ViewModel 必须检查更改是否真的适合他们。
- 另一种方式?
问题2:我也不确定我访问数据的地方是否选择得当。 PageViewModels 变得非常复杂,基本上可以做所有事情。所有 ViewModel 都需要了解我的架构中的数据层。
我一直在考虑使用 sqlite-net 取消数据访问并改用 Entity Framework 7。 这会解决上述问题吗,即它是否保证对象当我使用相同的上下文时,一个模型的身份?我还认为它会简化 ViewModel,因为我很少需要读取操作,因为这是通过导航属性完成的。
我也一直想知道在 MVVM 应用程序中使用两种方式的数据绑定是否是个好主意,因为它需要 属性 setter 来调用数据访问层来保存更改.只进行单向绑定并通过命令持久化所有更改是否更好?
如果有人可以对我的架构发表评论并提出改进建议,或者指出关注我的问题的 MVVM 架构的好文章,我将非常高兴。
- Have one ViewModel for the model? I don't think this makes much sense, as the master list needs only very little logic, and the detail view much more.
ViewModel 不依赖于模型。 ViewModel 使用模型来解决视图的需求。 ViewModel 是视图的单一联系点,因此无论视图需要什么,视图模型都必须提供。所以它可以是单个 model/multiple 模型。但是您可以将单个 ViewModel 分解为多个子 ViewModel,以使逻辑更简单。它的详细信息窗格可以分离到具有自己的视图模型的用户控件中。您的母版页将只有 window 将托管此控件,而 MasterViewmodel 会将责任推给子 ViewModel。
- Let the model implement INotifyPropertyChanged and thus propagate the change to the ViewModels? The problem I have with this, is that
the data layer currently doesn't guarantee that the objects it returns
for two read operations on one model id are identical - they just
contain the data read from the database and are newly created when
they are read (I think that's the way sqlite-net works). I'm also not
really sure how to avoid memory leaks happening because of all the
PropertyChanged event subscriptions from the ViewModels. Should I
implement IDisposable and let the PageViewModel call its children's
Dispose() method?
危险不在于使用 INotifyPropertyChanged
,但正如您所说的那样,它与订阅和取消订阅有关。无论何时需要订阅任何事件 - 不仅 INotifyPropertyChanged
你需要使用 IDisposable
来取消订阅它自己和它的子 ViewModels。我不清楚你描述的数据层,但如果它发布 属性 更改事件进行任何修改,我没有看到使用 INotifyPropertyChanged
有任何问题。
3.I currently have a DataChanged event on my data access layer. It is called whenever a create, update or delete operation occurs. Each
ViewModel that can be displayed simultaneously listens to this event,
checks whether the changed model is the one its the ViewModel for and
then updates its own properties. Again I have the problem of the
memory leak and this becomes slow, as too many ViewModels have to
check whether the change is really for them.
正如我之前所说,如果您为所有模型正确处理 subscribe/unsubscribe,则无需担心 INotifyPropertyChanged 的性能问题。但是可能会增加问题的是您为请求数据而对数据库进行的调用次数。您是否考虑过使用 Async...Await 数据访问层,它不会阻止 UI 进行任何更新。即使数据更新很慢,一个不会被数据调用阻塞的反应式 UI 也是更好的选择。
因此,请尝试添加在 DAL 层上抽象的数据访问服务,并提供一种异步方法来访问数据。也可以看看 Mediator Pattern。这可能会有所帮助。
I'm also not sure whether the place I access data is really well
chosen. The PageViewModels have become extremely convoluted and
basically do everything. And all ViewModels require knowledge of the
data layer with my architecture.
我看到了 2 个主要问题,
- 如果您觉得 PageViewModel 太大,请分解为可管理大小的子视图模型。这是非常主观的,所以你必须尝试看看所有部分都可以分解成它自己的 component/usercontrol 和它自己的视图模型。
- 当你说 ViewModels 需要数据层的知识,我希望你的意思是它们依赖于管理 DAL 层服务的接口并且不能直接访问 class 使用 CRUD 方法。如果不尝试添加一个抽象层,您实际上会在视图模型中执行此操作。这将处理 DAL CRUD 操作。
I've been thinking of scrapping data access with sqlite-net and using
Entity Framework 7 instead.
在没有确凿证据的情况下,不要尝试用 EF 替换 sqlite-net。在尝试进行如此大的更改之前,您需要衡量应用程序的性能。如果问题出在您的代码而不是您正在使用的组件上怎么办。首先尝试解决上述问题,然后您可以通过接口隔离 DAL 层,并在需要时替换它。
I've also been wondering whether having two way databinding is good
idea at all in a MVVM application, as it requires the property setter
to call the data access layer to persist the changes. Is it better to
do only one-way binding and persist all changes through commands?
如果您每次更改字段/每次击键时都直接调用数据库,那么这是一个问题。然后您应该有一个数据模型的副本,并且只有在您单击保存按钮时才保留更改。
我对涉及数据访问的 MVVM 应用程序(以前称为 WinRT,现在面向 UWP)的体系结构感到很困惑。我非常不确定如何在 UI 中传播更改以及在何处访问数据层。
基本架构如下:
- 模型层: 包含只有自动属性的模型(没有引用其他模型的导航属性,只有 ID;所以它们基本上只是数据库的表示)。他们没有实现 INotifyPropertyChanged。
- 数据访问层:一个使用sqlite-net在数据库中存储模型的存储库。它公开了基本的 CRUD 操作。它 returns 并从模型层接受模型。
- 视图模型:
- 模型的 ViewModels:它们环绕模型并公开属性。有时我将控件(例如文本框)的内容双向绑定到属性。 setter 然后访问数据层以保留此更改。
- View 的 PageViewModels:它们包含上面的 ViewModels 和命令。许多命令在进行数据访问、执行域特定逻辑和更新 PageViewModels 属性时变得很长。
- 视图(页面):它们绑定到 PageViewModel,并通过 DataTemplate 绑定到模型的 ViewModel。有时有双向数据绑定,有时我使用命令。
我现在对这个架构有几个问题:
问题一:一个模型可以出现在几个宫殿的屏幕上。例如,显示一个类型的所有可用实体列表的主从视图。用户可以 select 其中之一,其内容显示在详细信息视图中。如果用户现在在详细视图中更改 属性(例如模型名称),则更改应立即反映在主列表中。这样做的最佳方法是什么?
- 有模型的一个 ViewModel?我认为这没有多大意义,因为主列表只需要很少的逻辑,而详细视图则需要更多。
- 让 模型实现 INotifyPropertyChanged 从而将更改传播到 ViewModels?我遇到的问题是,数据层目前不保证它 returns 对一个模型 id 进行两次读取操作的对象是相同的——它们只包含从数据库读取的数据并且是新创建的当它们被阅读时(我认为这就是 sqlite-net 的工作方式)。我也不太确定如何避免由于来自 ViewModel 的所有 PropertyChanged 事件订阅而发生内存泄漏。我是否应该实施 IDisposable 并让 PageViewModel 调用其子项的 Dispose() 方法?
- 我目前在我的数据访问层 上有一个 DataChanged 事件。只要发生创建、更新或删除操作,就会调用它。每个可以同时显示的 ViewModel 都会监听这个事件,检查更改的模型是否是它的 ViewModel 对应的模型,然后更新自己的属性。我再次遇到内存泄漏的问题,这变得很慢,因为太多的 ViewModel 必须检查更改是否真的适合他们。
- 另一种方式?
问题2:我也不确定我访问数据的地方是否选择得当。 PageViewModels 变得非常复杂,基本上可以做所有事情。所有 ViewModel 都需要了解我的架构中的数据层。
我一直在考虑使用 sqlite-net 取消数据访问并改用 Entity Framework 7。 这会解决上述问题吗,即它是否保证对象当我使用相同的上下文时,一个模型的身份?我还认为它会简化 ViewModel,因为我很少需要读取操作,因为这是通过导航属性完成的。
我也一直想知道在 MVVM 应用程序中使用两种方式的数据绑定是否是个好主意,因为它需要 属性 setter 来调用数据访问层来保存更改.只进行单向绑定并通过命令持久化所有更改是否更好?
如果有人可以对我的架构发表评论并提出改进建议,或者指出关注我的问题的 MVVM 架构的好文章,我将非常高兴。
- Have one ViewModel for the model? I don't think this makes much sense, as the master list needs only very little logic, and the detail view much more.
ViewModel 不依赖于模型。 ViewModel 使用模型来解决视图的需求。 ViewModel 是视图的单一联系点,因此无论视图需要什么,视图模型都必须提供。所以它可以是单个 model/multiple 模型。但是您可以将单个 ViewModel 分解为多个子 ViewModel,以使逻辑更简单。它的详细信息窗格可以分离到具有自己的视图模型的用户控件中。您的母版页将只有 window 将托管此控件,而 MasterViewmodel 会将责任推给子 ViewModel。
- Let the model implement INotifyPropertyChanged and thus propagate the change to the ViewModels? The problem I have with this, is that the data layer currently doesn't guarantee that the objects it returns for two read operations on one model id are identical - they just contain the data read from the database and are newly created when they are read (I think that's the way sqlite-net works). I'm also not really sure how to avoid memory leaks happening because of all the PropertyChanged event subscriptions from the ViewModels. Should I implement IDisposable and let the PageViewModel call its children's Dispose() method?
危险不在于使用 INotifyPropertyChanged
,但正如您所说的那样,它与订阅和取消订阅有关。无论何时需要订阅任何事件 - 不仅 INotifyPropertyChanged
你需要使用 IDisposable
来取消订阅它自己和它的子 ViewModels。我不清楚你描述的数据层,但如果它发布 属性 更改事件进行任何修改,我没有看到使用 INotifyPropertyChanged
有任何问题。
3.I currently have a DataChanged event on my data access layer. It is called whenever a create, update or delete operation occurs. Each ViewModel that can be displayed simultaneously listens to this event, checks whether the changed model is the one its the ViewModel for and then updates its own properties. Again I have the problem of the memory leak and this becomes slow, as too many ViewModels have to check whether the change is really for them.
正如我之前所说,如果您为所有模型正确处理 subscribe/unsubscribe,则无需担心 INotifyPropertyChanged 的性能问题。但是可能会增加问题的是您为请求数据而对数据库进行的调用次数。您是否考虑过使用 Async...Await 数据访问层,它不会阻止 UI 进行任何更新。即使数据更新很慢,一个不会被数据调用阻塞的反应式 UI 也是更好的选择。
因此,请尝试添加在 DAL 层上抽象的数据访问服务,并提供一种异步方法来访问数据。也可以看看 Mediator Pattern。这可能会有所帮助。
I'm also not sure whether the place I access data is really well chosen. The PageViewModels have become extremely convoluted and basically do everything. And all ViewModels require knowledge of the data layer with my architecture.
我看到了 2 个主要问题,
- 如果您觉得 PageViewModel 太大,请分解为可管理大小的子视图模型。这是非常主观的,所以你必须尝试看看所有部分都可以分解成它自己的 component/usercontrol 和它自己的视图模型。
- 当你说 ViewModels 需要数据层的知识,我希望你的意思是它们依赖于管理 DAL 层服务的接口并且不能直接访问 class 使用 CRUD 方法。如果不尝试添加一个抽象层,您实际上会在视图模型中执行此操作。这将处理 DAL CRUD 操作。
I've been thinking of scrapping data access with sqlite-net and using Entity Framework 7 instead.
在没有确凿证据的情况下,不要尝试用 EF 替换 sqlite-net。在尝试进行如此大的更改之前,您需要衡量应用程序的性能。如果问题出在您的代码而不是您正在使用的组件上怎么办。首先尝试解决上述问题,然后您可以通过接口隔离 DAL 层,并在需要时替换它。
I've also been wondering whether having two way databinding is good idea at all in a MVVM application, as it requires the property setter to call the data access layer to persist the changes. Is it better to do only one-way binding and persist all changes through commands?
如果您每次更改字段/每次击键时都直接调用数据库,那么这是一个问题。然后您应该有一个数据模型的副本,并且只有在您单击保存按钮时才保留更改。