tags:

views:

1197

answers:

5

Hi,

We're using the DTO pattern to marshal our domain objects from the service layer into our repository, and then down to the database via NHibernate.

I've run into an issue whereby I pull a DTO out of the repository (e.g. CustomerDTO) and then convert it into the domain object (Customer) in my service layer. I then try and save a new object back (e.g. SalesOrder) which contains the same Customer object. This is in turn converted to a SalesOrderDTO (and CustomerDTO) for pushing into the repository.

NHibernate does not like this- it complains that the CustomerDTO is a duplicate record. I'm assuming that this is because it pulled out the first CustomerDTO in the same session and because the returning has been converted back and forth it cannot recognise this as the same object.

Am I stuck here or is there a way around this?

Thanks

James

A: 

How do you save the entity ?

Frederik Gheysels
Using session.SaveOrUpdate(SalesOrder)
James
+2  A: 

You can re-attach an object to a session in NHibernate by using Lock - e.g.

_session.Lock(myDetachedObject, NHibernate.LockMode.None);

which may or may not help depending on exactly what is happening here. On a side note, using DTO's with NHibernate is not the most common practice, the fact that NHibernate (mostly) supports persistence ignorance means that typically DTO's aren't as widely used as with some other ORM frameworks.

Steve Willcock
Thanks for the reply. I am using DTOs because my domain objects do not have public set methods on their properties. I then use a factory to create my domain objects from the DTOs.I suppose my problem is going to be knowing which objects need to be reattached and which are new. Maybe I need to rethink my approach :(
James
DTOs are also often necessary when you have a domain object for which some its data is stored in one place, and some in another (for example DB and XML files, respectively). This is the type of complexity that sample implementations of data mappers and repositories almost never even acknowledge. I'd recommend reading Martin Fowler's PoEAA to fill in the gaps: http://is.gd/NmTt
Chris Ammerman
+1  A: 

It's really about how NHibernate session works. So if you within a session pull an instance of your CustomerDTO and then after a while you should get the same CustomerDTO (say by primary key) - you actually will get reference to the very same object like you did in your first retrieval.

So what you do is that you either merge the objects by calling session.Merge or you ask your session for the object by calling session.Get(primaryKey) do your updates and flush the session.

However as suggested by Steve - this is not usually what you do - you really want to get your domain object from the datastore and use DTOs (if neede) for transferring the data to UI, webservice whatever...

Rashack
+1  A: 

I'm assuming that this is because it pulled out the first CustomerDTO in the same session and because the returning has been converted back and forth it cannot recognise this as the same object.

You are right. Hibernate can't. Consider implementing Equals and Hashcode to fix this. I think a re-attach may only work if you haven't loaded the object within this session.

zoidbeck
+1  A: 

As others have noted, implementing Equals and GetHashCode is a step in the right direction. Also look into NHibernate's support for the "attach" OR/M idiom.

You also have the nosetter.camelcase option at your disposal: http://davybrion.com/blog/2009/03/entities-required-properties-and-properties-that-shouldnt-be-modified/

Furthermore, I'd like to encourage you not to be dissuaded by the lack of information out there online. It doesn't mean you're crazy, or doing things wrong. It just means you're working in an edge case. Unfortunately the biggest consumers of libraries like NHibernate are smallish in-house and/or web apps, where there exists the freedom to lean all your persistence needs against a single database. In reality, there are many exceptions to this rule.

For example, I'm currently working on a commercial desktop app where one of my domain objects has its data spread between a SQL CE database and image files on disk. Unfortunately NHibernate can only help me with the SQL CE persistence. I'm forced to use a sort of "Double Mapping" (see Martin Fowler's "Patterns of Enterprise Application Architecture" http://is.gd/NmTt ) map my domain model through a repository layer that knows what data goes to NHibernate and what to disk.

It happens. It's a real need. Sometimes an apparent lack in a tool indicates you're taking a bad approach. But sometimes the truth is that you just truly are in an edge case, and need to build out some of these patterns for yourself to get it done.

Chris Ammerman