views:

354

answers:

2

How can I make such behaviuor in NHibernate:

There is an entity called User in my domain

// I ommit mapping attributes
public class User
{
  int Id {get; set;}
  int pId {get; set;}
  //....other props, such as Login, Name, email...
}

I need to make full copy of it, when updating. pId must be set to original Id. Old entity must be untouched.

So this must be like some versioning system, where pId - is immutable identity, and Id - is like version. I`ve tried to use Version mapping attribute, but it just updates Version field, withou recreating full entity. What approach will be better?

A: 

Depending on whether history is NOT part of your domain logic I'd suggest using triggers. By not being part of domain logic I mean - you don't need to show it to users, you don't make copies out of historical version.

By using triggers you have several options - the simplest (and implying that you really need to save history only for handful of tables) - would be having a separate _history table that's a copy of your original table.

All in all it really depends on what exactly you are after.

Rashack
trigger in DB is great, but is it possible to make NHibernate know about this recreation? So I just call myuser.Update(); and after update, myuser is already another recreated instance?
Alkersan
I need transparent replacement of entity when it changes
Alkersan
+1  A: 

I wrote a versioning system for our application. I split the versioned object into two classes, one that represents the whole object and one for its versions.

In our software, the versioning is part of the business logic. The application provides access to the history and the user has some control over the versioning.

A new version is therefore created in memory. You need to perform a deep-copy. You could implement this by implementing an interface in the root entity and all its children. This interface provides a method DeepCopy which is recursively called through the object graph.

There is also a protected MemberwiseCopy method in object, which could be helpful. It does not a deep copy.

We didn't want the pain to maintain the code which copies each single property. So we are using serialization to copy an object graph in memory:

public static T CopyDataContract<T>(T obj)
{
    NetDataContractSerializer serializer = new NetDataContractSerializer();
    using (MemoryStream stream = new MemoryStream())
    {
     serializer.Serialize(stream, obj);
     stream.Position = 0;
     return (T)serializer.Deserialize(stream);
    }
}

Additionally, we have methods in the entities which reset the ids and do some other cleanup. This is also done recursively though the object graph.

For now, it works fine. In the future we probably need to refactor it to the interface implementation, which is a bit cleaner.

Stefan Steinegger