These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Does anyone know of a NH pattern to solve this?
PostPosted: Mon Aug 14, 2006 2:50 am 
Newbie

Joined: Fri Apr 21, 2006 5:33 pm
Posts: 12
This issue has had me perplexed for some time now. If anyone could shed some light on how to achieve the following, I would be extremely grateful.

I have a WinForms app, which uses the standard TreeView/ListView layout (like Windows Explorer). As you can imagine, objects are drawn in the treeview so that child objects appear as subnodes. Whenever the user clicks a treenode, an editable listview is populated with the properties of the selected object:
Code:
Customer 1
|- Addresses
|   |- Address 1
|   |- Address 2
|   |- Address 3
|
|+ Orders

The user may modify the objects in any order they wish, so they might do this:
    1) User edits Customer.Name
    2) User edits Address1.ZipCode
    3) User saves/commits Address1
    4) User cancels Customer
If I use one session to read/write the objects, the changes to the Customer object get persisted, even though they shouldn't. I've tried to tackle this by using 2 sessions - a main 'read-only' session, and a temporary 'save' session:
Code:
ISession mainSession = SessionFactory.OpenSession();

object load(object obj)
{
    return mainSession.Load(obj);
}

void save(object obj)
{
    ISession saveSession = SessionFactory.OpenSession();
    ITransaction txn = saveSession.BeginTransaction();

    // Move the object from the main session into the local session:
    mainSession.Evict(obj);
    saveSession.Lock(obj);

    saveSession.SaveOrUpdate(obj
    txn.Commit();

    // Move the object back into the main session:
    saveSession.Evict(obj);
    mainSession.Lock(obj);
}


This doesn't work either. Because the object isn't modified in the 'save' session, NH doesn't detect any changes, and therefore nothing gets saved to the database.

Some other points to note:
    a) I want to keep the idea of a 'read' session. Not only does it act as a cache, but if a save operation fails in a different session, I don't have to discard all of the other objects that the user might have loaded.
    b) I have tried using the 'command pattern', where I record all of the changes made to the domain objects, and replay them within a 'save' session. The danger is that I could potentially end up calling code twice (e.g "Send an email when the order status has been updated" should only happen once).

Does anyone have ideas on how to accomplish this? Or is beyond the scope of what NHibernate can currently do?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 14, 2006 6:20 am 
Senior
Senior

Joined: Wed Jun 15, 2005 4:17 am
Posts: 156
From my point of view you try to hard to implement business rules through hibernate. hibernate is just the persistence layer it shouldn't be involved in enforcing business rules. Implement your command pattern, add the business rules (i.e. don't send the email twice) but do everything in your business layer code, only when you're done persist the objects.


Hope this helps,
Radu


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 14, 2006 1:17 pm 
Newbie

Joined: Fri Apr 21, 2006 5:33 pm
Posts: 12
I'm not sure that I understand your reply. I'm not trying to 'implement the business rules' through NHibernate - the rules are implemented in the domain object. I don't want to create a separate 'business object' and 'data object' - I want a single Domain Object to fulfill both objectives. It's the persisting of the domain object that is causing the problem.

I thought of another scenario which describes the problem better (I think!):
Code:
Customer 1
|- Addresses
|   |- Address 1
|   |- Address 2
|   |- Address 3
|
|+ Orders

    1) User edits Address1.ZipCode
    2) User edits Customer.Name
    3) User saves/commits Address1
    4) User cancels the edits to Customer
    5) At this point only Address1 should be persisted, but Customer also gets saved (because it's within the same session?)

In the above sequence, how do I save Address1 without saving Customer?

Maybe part of the issue is down to the 'unit of work' principal of NH. It works well for Web apps, but not so well for WinForm apps. Along with that, I'm attempting a different style of UI - one which is less restrictive for the end user.

If I had a UI that was more restrictive (e.g. the user has to always save an object before moving onto another one), then I wouldn't have a problem ("session-in-view" pattern springs to mind). But I want to allow the user to edit any object in any order, and then save the objects in any order.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 14, 2006 1:47 pm 
Senior
Senior

Joined: Wed Jun 15, 2005 4:17 am
Posts: 156
Vij wrote:
ls the edits to Customer
5) At this point only Address1 should be persisted, but Customer also gets saved (because it's within the same session?)[/list]


if you save the Address1 and Customer is also saved this is because of how the mappings are declared (the cascading attribute) and not because they share the same session.
Regarding the unit of work issue, you already know the answer: the command pattern. A command is a unit of work.

HTH,
Radu


Top
 Profile  
 
 Post subject: Session for Winforms
PostPosted: Wed Aug 16, 2006 2:02 pm 
Beginner
Beginner

Joined: Wed Aug 09, 2006 10:15 am
Posts: 20
Location: Vitoria - ES - Brazil
Vij,

This is the million dolar question. Everybody wants to know it.

So far, the simplest solution I found for this problem in this forum is to make your classes non-lazy and to implement your own LazyObjectCollection which can have an internal session to bring objects from database everytime it is requested.


Top
 Profile  
 
 Post subject: Save/Cancel Changes
PostPosted: Thu Aug 17, 2006 3:37 pm 
Newbie

Joined: Thu Aug 17, 2006 3:31 pm
Posts: 9
Vij,
One alternative can be taken from CSLA (Component Scalable Logical Archictecture). Everytime the user starts changing a portion of your object, you make a copy of the object by serializing it and pushing it on a stack of some sort. Then they can save, edit, save, etc. When they cancel, you pull the most recent copy off of the stack, which wipes out their most recent changes, then save that copy.

It takes some work, but Mr. Lhotka presents what I think is a viable solution.

Hope that helps in some way/shape/form.

-Bill


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.