NHibernate:ISession.Merge(对象)是NonUniqueObjectException的好解决方案吗?

时间:2017-01-09 09:58:29

标签: nhibernate

我的应用程序分为三层。 DAL (NHibernate) => BLL => Application

DAL返回Entity个实例。这些是NHibernate实体。 BLL将这些映射到DTO并返回到应用程序。应用程序使用DTO;它永远不会创建/使用实体。

反向也是一样的。对于插入/更新,应用程序创建DTO并将其传递给BLL。 BLL将其映射到Entity并将其传递给DAL。 DAL然后进行行动。

这很好,而不是问题。问题是当更新记录时,如果会话缓存中已存在具有相同ID的实体,则会抛出NonUniqueObjectException异常。

dbConnection = OpenNHibernateSession();
ConfigService configService = new ConfigService(dbConnection);
ConfigDto configDto = configService.GetConfig();
configDto.Property1 = newValue;
configService.UpdateConfig(configDto);
dbConnection.Dispose();

步骤: -

  1. 开放会话
  2. 获取对象
  3. 修改对象
  4. 更新对象
  5. 关闭会话
  6. 在步骤2中检索的实体已在缓存中。应用程序修改DTO并将其传递给BLL进行更新。 BLL将其映射到实体,该实体创建实体的新实例。具有相同ID的实体已存在于会话中,因此是例外。

    在搜索StackOverflow时,我发现Merge是解决方案。我实现如下: -

    try
    {
        nhSession.Update(instance);
    }
    catch(NonUniqueObjectException)
    {
        nhSession.Merge(instance);
    }
    

    这是正确的实施吗?这种方法会出现什么问题?我可以将它用作常规/清洁解决方案吗?或者这只是一个黑客,我应该尽快用好的解决方案取代?

    如果这只是一个黑客攻击,请提出清洁解决方案。

    的参考文献:

1 个答案:

答案 0 :(得分:0)

我参考以下答案。虽然那些没有直接回答我的问题而且所有这些都属于Hibernate(Java),但仍然帮助我得出结论。

Ref1

  

merge()实际上不是(重新)附件API。注意merge()有返回值?这是因为它会返回托管图,而托管图可能不是您传递的图。

Ref2

  

通过调用merge(),瞬态或分离实例的状态也可以作为新的持久实例持久化。

Ref3

  

merge()会将陈旧状态推送到数据库,并覆盖任何干预更新。

所以我的新代码只处理Merge()方法的返回值。

try
{
    nhSession.Update(instance);
}
catch(NonUniqueObjectException)
{
    instance = nhSession.Merge(instance);
}

<强>注意:

  1. 您必须确保会话缓存中的实例没有用,如果它被您通过merge()传入的新实例覆盖,则可以正常使用。您将丢失对会话缓存中的实例副本所做的所有更改。
  2. 如果会话缓存中的实例副本 标记为要删除 ,则可能会出错。
  3. 我还没有彻底测试过这个;但在最初的测试中,它运作良好。

    另一种解决方案:

    this回答中获取GetInstanceFromCache()方法。

    try
    {
        nhSession.Update(instance);
    }
    catch(NonUniqueObjectException)
    {
        T instanceFromCache = nhSession.GetInstanceFromCache<T>(instance);
        nhSession.Evict(instanceFromCache);
        nhSession.Update(instance);
    }
    

    结论:

    只要你对上面提到的注意没问题;这看起来是可以接受的解决方案。