使用多层MVVM处理数据库事务和TreeView中的异常。

时间:2023-01-29 16:27:44

Background:
I have a custom user control based around a WPF TreeView. I've been using the MVVM pattern and have a base view model TreeNode class and several derived view models such as LocationNode, LocationFolder, PersonNode, PersonFolder, CollectionNode, CollectionFolder, etc..

背景:我有一个基于WPF TreeView的自定义用户控件。我一直在使用MVVM模式,并有一个基本视图模型TreeNode类和一些派生的视图模型,如LocationNode、LocationFolder、PersonNode、PersonFolder、CollectionNode、CollectionFolder等。

A example of how the tree might be laid out is:

这棵树的布局的一个例子是:


- CollectionFolder
--> CollectionNode
    --> LocationFolder
        -->LocationNode
        -->LocationNode
    --> PersonFolder
        -->PersonNode
--> CollectionNode
--> CollectionNode
+ CollectionFolder
+ CollectionFolder   

When I perform drag and drop operations, each class handles the business logic, i.e. if I drop on a PersonNode on a CollectionNode, the CollectionNode view model contains the logic how on to add the PersonNode it its child PersonFolder.

当我执行拖放操作时,每个类都处理业务逻辑,例如,如果我在集合节点上的PersonNode上拖放,那么CollectionNode视图模型包含如何将PersonNode添加到它的子PersonFolder中的逻辑。

Problem:
Everything works great, I can drag and drop all over the place, and the code is nicely contained in the dervied classes. If I need to add an extra drop rule, I add it to the appropriate drop target view model.

问题:一切都很好,我可以到处拖放,代码很好地包含在dervied类中。如果我需要添加一个额外的drop规则,我将它添加到适当的drop目标视图模型中。

The problem is when a PersonNode is added to a PersonFolder I need to create a new database entry to reflect that the underlying Person model is now in also in a new Collection.

问题是,当一个PersonNode被添加到PersonFolder中时,我需要创建一个新的数据库条目来反映底层的Person模型现在也在一个新的集合中。

Currently, each view model in the tree has access to the current database session/transaction and can perform the insert/save. But this makes catching exceptions and errors extremely repeative, my exception handling code is being duplicated all over my view models. Is there a better way in MVVM to handle my database interactions?

当前,树中的每个视图模型都可以访问当前的数据库会话/事务,并可以执行插入/保存。但是这使得捕获异常和错误变得极其简单,我的异常处理代码在我的视图模型中被复制。MVVM中是否有更好的方法来处理数据库交互?

An code snippet from my Drop event in my PersonFolder

我的个人文件夹中的Drop事件的代码片段


// Create a new view model for the Person and add it to my children
_children.Add( new PersonNode( droppedPerson ) );

// Create a new entry in the collection for this person
CollectionEntry entry = new CollectionEntry();
entry.Entity = droppedPerson;
entry.Collection = _collection;

// Save the new entry
using( var transaction = _uow.BeginTransaction( IsolationLevel.Serializable ) )
{
    // Add the entry to the session
    _uow.Add( entry );

    // Save the session
    _uow.SaveChanges(); // [1]

    // Commit transaction
    transaction.Commit(); // [2]
}

[1] and [2] have the potential for throwing exceptions and should be handled in try/catch statements. However, I don't want to duplicate all my exception handling in all my view models, any suggestions?

[1]和[2]有可能抛出异常,应该在try/catch语句中处理。但是,我不想在我所有的视图模型中复制所有的异常处理,有什么建议吗?

I guess I could always implement a singleton to contain the session and exception handling and pass my new entities into that?

我想我总是可以实现一个单例来包含会话和异常处理,并将我的新实体传递给它?

1 个解决方案

#1


1  

I'm assuming that the variable part of your last code block is:

我假设你最后一个代码块的变量是:

_uow.Add( entry );

...so in some cases you might actually want significantly more or less actions to happen in that spot.

…所以在某些情况下,你可能会想要在那个地方发生很多或多或少的行动。

I think this is a good candidate for the "Hole in the Middle Pattern".

我认为这是“中间模式的漏洞”的一个很好的候选者。

Basically just pass an

基本上只是通过

Action<T>

to some other place (Singleton, whatever) that opens a transaction, passes the context (_uow) to your action, and then commits the transaction, and handles all your exception logic. Your code would look like:

将上下文(_uow)传递给操作,然后提交事务,并处理所有异常逻辑。您的代码应该是:


// Create a new view model for the Person and add it to my children
_children.Add( new PersonNode( droppedPerson ) );

// Create a new entry in the collection for this person
CollectionEntry entry = new CollectionEntry();
entry.Entity = droppedPerson;
entry.Collection = _collection;

someSingleton.Execute(o => o.Add(entry));

#1


1  

I'm assuming that the variable part of your last code block is:

我假设你最后一个代码块的变量是:

_uow.Add( entry );

...so in some cases you might actually want significantly more or less actions to happen in that spot.

…所以在某些情况下,你可能会想要在那个地方发生很多或多或少的行动。

I think this is a good candidate for the "Hole in the Middle Pattern".

我认为这是“中间模式的漏洞”的一个很好的候选者。

Basically just pass an

基本上只是通过

Action<T>

to some other place (Singleton, whatever) that opens a transaction, passes the context (_uow) to your action, and then commits the transaction, and handles all your exception logic. Your code would look like:

将上下文(_uow)传递给操作,然后提交事务,并处理所有异常逻辑。您的代码应该是:


// Create a new view model for the Person and add it to my children
_children.Add( new PersonNode( droppedPerson ) );

// Create a new entry in the collection for this person
CollectionEntry entry = new CollectionEntry();
entry.Entity = droppedPerson;
entry.Collection = _collection;

someSingleton.Execute(o => o.Add(entry));