我的应用程序分为三层。 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();
步骤: -
在步骤2中检索的实体已在缓存中。应用程序修改DTO并将其传递给BLL进行更新。 BLL将其映射到实体,该实体创建实体的新实例。具有相同ID的实体已存在于会话中,因此是例外。
在搜索StackOverflow时,我发现Merge
是解决方案。我实现如下: -
try
{
nhSession.Update(instance);
}
catch(NonUniqueObjectException)
{
nhSession.Merge(instance);
}
这是正确的实施吗?这种方法会出现什么问题?我可以将它用作常规/清洁解决方案吗?或者这只是一个黑客,我应该尽快用好的解决方案取代?
如果这只是一个黑客攻击,请提出清洁解决方案。
答案 0 :(得分:0)
我参考以下答案。虽然那些没有直接回答我的问题而且所有这些都属于Hibernate(Java),但仍然帮助我得出结论。
merge()
实际上不是(重新)附件API。注意merge()
有返回值?这是因为它会返回托管图,而托管图可能不是您传递的图。
通过调用
merge()
,瞬态或分离实例的状态也可以作为新的持久实例持久化。
merge()
会将陈旧状态推送到数据库,并覆盖任何干预更新。
所以我的新代码只处理Merge()
方法的返回值。
try
{
nhSession.Update(instance);
}
catch(NonUniqueObjectException)
{
instance = nhSession.Merge(instance);
}
<强>注意:强>
merge()
传入的新实例覆盖,则可以正常使用。您将丢失对会话缓存中的实例副本所做的所有更改。我还没有彻底测试过这个;但在最初的测试中,它运作良好。
从this回答中获取GetInstanceFromCache()
方法。
try
{
nhSession.Update(instance);
}
catch(NonUniqueObjectException)
{
T instanceFromCache = nhSession.GetInstanceFromCache<T>(instance);
nhSession.Evict(instanceFromCache);
nhSession.Update(instance);
}
只要你对上面提到的注意没问题;这看起来是可以接受的解决方案。