wpf MVVM 中的 ObservableCollection 和 Repository 模式 - 如何关联它们,以及“更新”方法的案例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19405541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:52:35  来源:igfitidea点击:

ObservableCollection and Repository pattern in MVVM - How to relate them, and a case for the "Update" method

wpfmvvmrepository-patternobservablecollection

提问by heltonbiker

My Desktop WPF application has a repository (of type Person) which resides in the Model layer, and is called by a ViewModel which has a PersonListproperty which is databound to a DataGrid.

我的桌面 WPF 应用程序有一个存储库(类型为Person),它驻留在模型层中,并由具有数据PersonList绑定到DataGrid.

When I open my Application, the list is shown by default. During initialization, the following code applies:

当我打开我的应用程序时,默认情况下会显示该列表。在初始化期间,以下代码适用:

public class PersonScreenViewModel : ViewModelBase
{
    PersonRepository _person_repository;

    public ObservableCollection<Person> PersonList { get; set; }

    public PersonScreenViewModel() {

        _repositorio_pacientes = new RepositorioPacientes();

        PersonList = new ObservableCollection<Person>(_person_repository.GetAll());
    }

    // ... ///
}

My doubts are based on some difficulty to understand how to implement "Save / Update" method(s).

我的怀疑是基于理解如何实现“保存/更新”方法的一些困难。

Every text about the Repository pattern tells that "the repository should behave like a collection of [ entities | domain objects ]". So, the most logical thing would be to databind the repository itself to the DataGrid. That could be done if I created a class which inherit from ObservableCollectionand implements repository logic. Currently, what I do is take a copy of the repository items, using _repo.GetAll(), and work in that copy, having to commit back after my changes are done.

关于 Repository 模式的每个文本都告诉我们“存储库应该表现得像一个 [实体 | 域对象] 的集合”。因此,最合乎逻辑的事情是将存储库本身数据绑定到DataGrid. 如果我创建了一个继承ObservableCollection并实现存储库逻辑的类,就可以做到这一点。目前,我所做的是获取存储库项目的副本,使用_repo.GetAll(),并在该副本中工作,必须在我的更改完成后提交回来。

Specifically, my workflow involves selecting a row in the DataGrid, changing some properties of the selected object, and commiting these changes, expecting that the same object is persisted with the new property values.

具体来说,我的工作流程涉及在 DataGrid 中选择一行,更改所选对象的某些属性,并提交这些更改,期望使用新的属性值持久保存相同的对象。

Usually, if you take an object in a collection and modify it, you don't need to "update" anything, since you already changed the object itself.

通常,如果您获取集合中的对象并对其进行修改,则不需要“更新”任何内容,因为您已经更改了对象本身。

The question is: "How can I data bind my view to the repository itself? Should the repo inherit from ObservableCollection? How is it supposed to be done? Is some part of my reasoning flawed?"

问题是:“我如何将数据绑定到存储库本身?存储库是否应该继承自ObservableCollection?它应该如何完成?我的推理的某些部分是否有缺陷?”

It is important to say that my application is not data-oriented, the Personclass is very basic (POCO marked as [Serializable], with a few properties), and my repository uses plain XML serialization and the filesystem structure.

重要的是,我的应用程序不是面向数据的,Person类非常基础(POCO 标记为[Serializable],具有一些属性),并且我的存储库使用纯 XML 序列化和文件系统结构。

Thanks for reading!

谢谢阅读!

回答by Sheridan

In my personal opinion, what you are currently doing is correct... it is generally good practice to have some separation between the various layers of your application; Models, View Models, Views and DataAccess (sometimes combined into Models). Having said that, it really depends on your application... it might not be worth doing this on small applications as it adds a lot of code and time to set up and maintain.

在我个人看来,您目前所做的是正确的……在应用程序的各个层之间进行一些分离通常是一种很好的做法;模型、视图模型、视图和数据访问(有时组合成模型)。话虽如此,这确实取决于您的应用程序......在小型应用程序上这样做可能不值得,因为它会增加大量代码和时间来设置和维护。

However, the main reasons for providing this separation (called separation of concerns) is to enable unit tests to be able to test the individual layers without concerning the other layers. For example, if we wanted to write unit tests for our view models, we wouldn't want to test their functionality on the actual data objects in the database. If we have this separation (through the use of interfaces) then we can simply mock up data objects to use during these tests.

然而,提供这种分离(称为关注点分离)的主要原因是使单元测试能够在不考虑其他层的情况下测试各个层。例如,如果我们想为我们的视图模型编写单元测试,我们不想在数据库中的实际数据对象上测试它们的功能。如果我们有这种分离(通过使用接口),那么我们可以简单地模拟数据对象以在这些测试中使用。

Another reason, although less common in practice, is to enable whole layers to be 'swapped out' without affecting the code in the other layers. Examples of this would include changing the database used in the application, or maybe changing the views from a desktop application into web pages in a web application. If we have separate layers, then these changes won't affect the other layers.

另一个原因,虽然在实践中不太常见,但可以在不影响其他层的代码的情况下“换出”整个层。这方面的示例包括更改应用程序中使用的数据库,或者可能将视图从桌面应用程序更改为 Web 应用程序中的网页。如果我们有单独的层,那么这些更改不会影响其他层。

So to answer your question directly, I wouldn't bind your views to the repositories at all... keep your current separation. After all, how long does it take to copy a collection sourced from the database into a view collection property?

因此,为了直接回答您的问题,我根本不会将您的观点绑定到存储库...保持当前的分离状态。毕竟,将源自数据库的集合复制到视图集合属性需要多长时间?

UPDATE >>>

更新 >>>

I'm not sure that I fully understand the question in your comment. I'm guessing that you are binding your PersonListproperty in your view model to the DataGrid.ItemsSourceproperty to display the data. Any changes made in the DataGridshould affect the items in your PersonList. If you were to add a 'Save' Button, then you could update the database in that click or command handler.

我不确定我是否完全理解您评论中的问题。我猜您正在PersonList将视图模型中的DataGrid.ItemsSource属性绑定到该属性以显示数据。中所做的任何更改都DataGrid应该影响PersonList. 如果要添加 'Save' Button,则可以在该单击或命令处理程序中更新数据库。

If you were enquiring how to find out which elements had been changed, there are several methods for accomplishing this. There is a good tip in the How to get only modified Items from WPF Data Gridpost here, but I prefer to use a duplicate collection and just compare them to find the changed elements (you'd need to implement the Equalsmethod for this to work).

如果您想知道如何找出哪些元素已更改,则有多种方法可以完成此操作。How to get only modified Items from WPF Data Gridpost here中有一个很好的提示,但我更喜欢使用重复的集合并只比较它们以找到更改的元素(您需要实现该Equals方法才能工作)。

Please let me know if that does not answer your question.

如果这不能回答您的问题,请告诉我。

回答by 123 456 789 0

"Every text about the Repository pattern tells that "the repository should behave like a collection of [ entities | domain objects ".

“关于存储库模式的每个文本都告诉我们“存储库应该表现得像一个 [实体 | 的集合”。域对象”。

What you originally have is sort of correct. First of all ObservableCollection works perfectly with the View because every add/update/delete will automatically propagate back to the user interface. If you implemented it with repository, then you would have to go call the databasereload the control bound to your repository

你最初拥有的东西是正确的。首先,ObservableCollection 与 View 完美配合,因为每次添加/更新/删除都会自动传播回用户界面。如果您使用存储库实现它,那么您将不得不调用数据库重新加载绑定到您的存储库的控件

"How can I data bind my view to the repository itself? Should the repo inherit from ObservableCollection? How is it supposed to be done? Is some part of my reasoning flawed?"

“我如何将数据绑定到存储库本身?存储库是否应该从 ObservableCollection 继承?它应该如何完成?我的推理的某些部分有缺陷吗?”

  • You don't want to data bind the Repository to the DataGrid itself, because you lose cachingand every time the user loads the user control you always have a trip back to your database.
  • You don't want to inherit a repository to an ObservableCollection, ObservableCollection has more overhead vs simple IEnumerablegiven you already database returned you a collection already.
  • You always don't want ObservableCollection as your collection for your data because it is expensive. A simple enumerable of data is enough depending on your scenario (Read-only data).
  • 您不想将 Repository 数据绑定到 DataGrid 本身,因为您会丢失缓存,并且每次用户加载用户控件时,您总是会返回到您的数据库。
  • 您不想将存储库继承到 ObservableCollection,ObservableCollection 比简单的 IEnumerable 有更多的开销,因为数据库已经返回给您一个集合。
  • 你总是不希望 ObservableCollection 作为你的数据集合,因为它很昂贵。根据您的场景(只读数据),简单的数据枚举就足够了。