views:

53

answers:

1

Hello:

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..

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.

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.

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.

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?

An code snippet from my Drop event in my PersonFolder


// 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?

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

A: 

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:


// 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));

Scott Whitlock