6

我使用 NHibernate 将类 Person 映射到数据库。我从数据库加载对象并将其发送到不同的客户端。第一个客户将修改 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();
        }
    }
}

PS:对不起我的英语不好

4

4 回答 4

15

实际上,您可以告诉 NHibernate 使用Dynamic Update.

更多信息:http ://ayende.com/blog/3946/nhibernate-mapping-concurrency

于 2011-06-07T20:26:32.603 回答
3

这是一个并发问题。第二个客户端不知道数据在读取后发生了变化,因此他们的更改会覆盖第一个客户端的更改。这可以在 NHibernate 中通过几种方法之一来处理,其中最常见的是使用版本列。

这个问题很容易预防,更大的问题是在发生时向用户提供良好的反馈。

于 2011-06-07T16:16:22.273 回答
1

答案是:你不能。NH不知道只是名字变了。

您可以通过不允许并发编辑来避免它。例如通过 NH 的乐观锁定机制。第二个客户将获得一个StaleObjectStateException.

如果两个客户端的编辑实际上不是同时进行的(而是都基于相同的对象状态),则需要确保第二个客户端在编辑之前获得第一个客户端的更改。例如,通过在打开编辑器之前检索实际状态或从服务器发送更改通知。

如果你想保持并发编辑,你还有很多工作要做。客户需要提供实际更改的信息。然后您只需要复制这些值。这是一项艰苦的工作。那么您可能仍然会遇到这样合并的值不适合的问题。

于 2011-06-07T17:47:18.647 回答
0

正如 Jamie Ide 正确指出的那样,您遇到的是并发问题,而不是映射问题。

当您创建对象的休眠映射时,一旦刷新会话,这些对象中存在的任何数据都将保存(或更新)在数据库中。您不能指定要更新的单个字段,要么全部要么什么都没有。

只是另一个(不相关的)点,您的示例代码正在对您的实体的每个操作实例化一个新的会话工厂。这通常是一个坏主意,因为创建会话工厂的成本很高。您最好通过全局上下文(单例)管理会话工厂,创建一次,并在需要时生成会话(重量较轻的对象)。

于 2011-06-07T17:00:38.460 回答