c# - MVVM体系结构: one model - several view models + place for data access

标签 c# entity-framework mvvm architecture

我对有关数据访问的MVVM应用程序(以前称为WinRT,现在针对UWP)的体系结构感到困惑。我不确定如何在UI上传播更改以及在何处访问数据层。

这是基本架构:

  • 模型层:包含仅具有自动属性的模型(没有引用其他模型的导航属性,仅是ID;因此它们基本上只是数据库的表示形式)。他们没有实现INotifyPropertyChanged。
  • 数据访问层:使用sqlite-net将模型存储在数据库中的存储库。它公开了基本的CRUD操作。它返回并接受来自模型层的模型。
  • ViewModels :

    :模型的ViewModel:环绕模型并公开属性。有时我将控件的内容(例如TextBoxes)双向绑定(bind)到属性。然后,设置者将访问数据层以保留此更改。
  • View 的PageViewModels :它们包含上方的ViewModel和命令。只要执行数据访问,执行特定于域的逻辑并更新PageViewModels属性,许多命令就变得非常长。
  • View (页面):它们绑定(bind)到PageViewModels并通过DataTemplate绑定(bind)到模型的ViewModels。有时有双向数据绑定(bind),有时我使用Commands。

  • 我现在在这个架构上遇到几个问题:

    问题1:在几个宫殿的屏幕上可以代表一种模型。例如,主从 View 显示一个类型的所有可用实体的列表。用户可以选择其中之一,其内容将显示在详细 View 中。如果用户现在在详细 View 中更改了属性(例如,模型的名称),则更改应立即反射(reflect)在主列表中。最好的方法是什么?
  • 模型是否有一个ViewModel?我认为这没有多大意义,因为主列表只需要很少的逻辑,而详细 View 则更多。
  • 模型实现INotifyPropertyChanged ,从而将更改传播到ViewModels吗?我的问题是,数据层当前不能保证在一个模型id上两次读取操作返回的对象是相同的-它们只包含从数据库读取的数据,并且在读取时是新创建的(我认为这就是sqlite-net的工作方式)。由于ViewModels中的所有PropertyChanged事件订阅,我也不太确定如何避免发生内存泄漏。我应该实现IDisposable并让PageViewModel调用其子级的Dispose()方法吗?
  • 我当前在数据访问层上有一个 DataChanged事件。每当发生创建,更新或删除操作时都会调用它。可以同时显示的每个ViewModel都监听此事件,检查更改的模型是否为其ViewModel所使用的模型,然后更新其自己的属性。再次,我遇到了内存泄漏的问题,并且它变得很慢,因为太多的ViewModel必须检查更改是否确实适合他们。
  • 另一种方法?

  • 问题2:我也不确定我访问数据的位置是否选择得当。 PageViewModels变得非常复杂,基本上可以完成所有操作。而且所有ViewModel都需要我的体系结构的数据层知识。

    我一直在考虑使用sqlite-net取消数据访问,而改用Entity Framework 7。 是否可以解决上述问题,即当我使用相同的上下文时,它可以保证一个模型的对象身份吗?我还认为这将简化ViewModel,因为我很少需要读取操作,因为这是通过导航属性完成的。

    我也一直想知道在MVVM应用程序中使用双向数据绑定(bind)是否是个好主意,因为它需要属性 setter 调用数据访问层才能保留更改。仅执行单向绑定(bind)并通过命令保留所有更改是否更好?

    如果有人可以对我的体系结构发表评论并提出改进建议或指向关注我的问题的MVVM体系结构的好文章,我将非常高兴。

    最佳答案

    1. 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使用该模型来满足 View 的需求。 ViewModel是 View 的单接触点,因此无论ViewModel需要提供什么 View 。因此它可以是单个模型/多个模型。但是您可以将单个ViewModel分解为多个子ViewModel,以简化逻辑。可以将其类似的详细信息 Pane 分为具有自己的 View 模型的用户控件。您的母版页上将只有一个窗口,它将托管此控件,而MasterViewmodel会将职责推送到子ViewModel。

    1. 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取消订阅自身及其子ViewModel。我在您描述的数据层上不清楚,但是如果它发布属性更改事件以进行任何修改,那么使用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.



    如前所述,如果您为所有模型正确处理订阅/取消订阅,则无需担心INotifyPropertyChanged的性能问题。但是,可能增加该问题的是您为请求数据而对数据库进行的调用次数。您是否考虑过将Async ... Await用于数据访问层,这将不会阻止UI进行任何正在发生的更新。即使数据更新很慢, react 性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太大,请分割为可管理大小的 subview 模型。它非常主观,因此您必须尝试查看可以使用自己的 View 模型将所有部分分解为自己的组件/用户控件。
  • 当您说ViewModels需要数据层知识时,我希望您的意思是它们依赖于管理DAL层服务的接口(interface),并且不能直接使用CRUD方法访问类。如果没有,请尝试添加一个在 View 模型中实际执行的抽象层。这将处理DAL CRUD操作。

  • I've been thinking of scrapping data access with sqlite-net and using Entity Framework 7 instead.



    没有确凿的证据,请勿尝试用EF替换sqlite-net。您需要先评估应用程序的性能,然后再尝试进行如此大的更改。如果问题出在代码而不是正在使用的组件上,该怎么办。首先尝试解决上述问题,然后可以通过接口(interface)隔离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?



    如果您每次每次对字段/进行更改时都直接调用数据库,那么这将是一个问题。然后,您应该具有数据模型的副本,并且仅在单击“保存”按钮时才保留更改。

    关于c# - MVVM体系结构: one model - several view models + place for data access,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35392335/

    相关文章:

    c# - 从字符串中删除以 SOT 开头并以 EOT 结尾的子字符串

    c# - .NET Core 和 .NET Standard 项目不进行增量构建

    .net - Dotnet EF 更新不生成数据库

    c# - Entity Framework 中的通用查询方法

    wpf - 我还如何使用Mvvm Light Toolkit将参数传递给新的打开的窗口

    c# - 在 Wow6432Node 和普通配置单元中创建注册表

    c# - 如何在c#中创建带有数据库的exe文件以在客户端计算机上运行

    c# - 了解代码优先虚拟属性

    c# - 在另一个线程中创建 WPF 命令

    c# - 有界元素的 ItemsSource 未在 View 中更新