我有一个使用NHibernate映射到数据库的Person。 我从DB加载对象并将其发送到不同的客户端。 第一个客户端将修改Name和Country属性。 第二个客户端将仅修改Name属性。 然后两者都将修改后的对象返回给服 当我从第一个客户端保存数据时 - 然后保存正确,两者 - 名称和国家/地区更新。 当我从第二个客户端保存数据时 - 我有问题。它覆盖了第一个客户端的数据并保存了新的名称和国家的初始值。
我如何告诉NHibernate只保存Name值而不覆盖Country值?
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:抱歉我的英文不好
答案 0 :(得分:14)
实际上,您可以告诉NHibernate使用Dynamic Update
专门更新“脏”字段。
更多信息:http://ayende.com/blog/3946/nhibernate-mapping-concurrency
答案 1 :(得分:2)
这是一个并发问题。第二个客户端在读取数据后不知道数据已更改,因此他们的更改会覆盖第一个客户端的更改。这可以通过several methods之一在NHibernate中处理,其中最常见的是使用版本列。
这个问题很容易预防,更大的问题是在用户发生时提供良好的反馈。
答案 2 :(得分:1)
答案是:你做不到。 NH不知道只有名字改变了。
您可以通过不允许并发编辑来避免它。例如,NH的乐观锁定机制。第二个客户端将获得StaleObjectStateException
。
如果两个客户端的编辑实际上不是同时进行(但都基于相同的对象状态),则需要确保第二个客户端在编辑之前获取第一个客户端的更改。例如,在打开编辑器之前检索实际状态,或者从服务器发送更改的通知。
如果你想保持并发编辑,你还有很多工作要做。客户需要提供实际已更改的信息。然后,您只需要复制这些值。这是一项艰苦的工作。那么你可能仍然有这样的合并值不适合的问题。
答案 3 :(得分:0)
正如Jamie Ide正确指出的那样,您遇到的是并发问题,而不是映射问题。
当您创建对象的nhibernate映射时,一旦刷新会话,这些对象中存在的任何数据都将在数据库中保存(或更新)。你不能指定要更新的单个字段,它是全部或全部。
只是另一个(不相关的)点,您的示例代码将在您的实体的每个操作上实例化一个新的会话工厂。这通常是一个坏主意,因为会话工厂的创建成本很高。最好通过全局上下文(单例)管理会话工厂,创建一次,并在需要时生成会话(权重较轻的对象)。