I have class Person mapped to database with NHibernate. I load objects from DB and send it to different clients. First client will modify Name and Country property. Second client will modify only Name property. Then both returns modified objects to server. When I save data from first client - then saved correctly, both - name and country updated. When I save data from second client - I have problem. It was override data from first client and save new name and initial value of country.
How I can tell NHibernate to save only Name value and not override Countr开发者_JS百科y value?
public class Person
{
public string Name { get; set; }
public string Country { get; set; }
}
public static List<Person> GetEntities()
{
var factory = CreateSessionFactory();
using (ISession session = factory.OpenSession())
{
return session.CreateCriteria<Person>().List<Person>();
}
}
public static void SaveEntities(List<Person> entities)
{
var factory = CreateSessionFactory();
using (ISession session = factory.OpenSession())
{
using (var t = session.BeginTransaction())
{
foreach (var person in entities)
{
session.Merge(person);
}
t.Commit();
}
}
}
P.S: Sorry for my bad english
Actually, you can tell NHibernate to specifically update the "dirty" fields using Dynamic Update
.
More on: http://ayende.com/blog/3946/nhibernate-mapping-concurrency
This is a concurrency problem. The second client doesn't know that the data has changed since they read it, so their changes overwrite the first client's changes. This can be handled in NHibernate by one of several methods, the most common of which is to use a version column.
This problem is easy to prevent, the bigger issue is providing good feedback to the user when it occurs.
The answer is: you can't. NH doesn't know that only the name changed.
You can avoid it by not allowing concurrent editing. For instance by NH's optimistic locking mechanism. The second client would get an StaleObjectStateException
.
If the editing of the two clients is actually not at the same time (but both based on the same object state), you need to make sure that the second client gets the changes of the first before editing. For instance by retrieving the actual state before opening the editor or by sending a changed notification from the server.
If you want to keep the concurrent editing, you have quite some work to do. The client needs to provide the information what actually had changed. Then you need to copy only these values. This is hard work. Then you may still have the problem that the so merged values don't fit.
As Jamie Ide correctly pointed out, what you're experiencing is a concurrency problem, not a mapping problem..
When you create your nhibernate mapping of your object, whatever data is present in those objects will be saved (or updated) in the database once the session is flushed. You can not designate individual fields to update, it's all or nothing.
Just another (unrelated) point, your sample code is instantiating a new session factory on each operation of your entity. This is generally a bad idea, since session factories are expensive to create. You're better off managing your session factory through a global context (singleton), create it once, and spawn sessions (which are lighter weight objects) when needed.
精彩评论