我在工作单元开始时开始会话,并在结束时关闭。工作单位是多种方法的共享点。
在一种方法中,我使用Get
方法加载实体。所以它位于会话缓存中。实体实例是方法的本地实例。因此,当方法范围结束时,实体实例不可访问。但是实体仍在会话缓存中。
现在,第二种方法创建实体的新实例并尝试删除它。这会按预期抛出NonUniqueObjectException
。
以下是我能想象到的解决方案,但无法实现:
public void Delete<T>(T instance) where T : BaseEntity
{
try
{
nhSession.Delete(instance);
}
catch(NonUniqueObjectException)
{
T instanceFromCache = GetInstanceFromCache<T>(instance);
nhSession.Evict(instanceFromCache);
nhSession.Delete(instance);
}
}
如果我能以某种方式从会话缓存中获取实体实例,我可以Evict
它,并希望问题能够得到解决。但我无法实现我想象的GetInstanceFromCache
方法。
我尝试使用nhSession.Get
,但这在我的方案中没有帮助。我的数据库中的主键列名称不是“id”,并且它在表之间也不相同。在一个表中,它是“Field1”,在另一个表中是“Field2”。所以我不能使用像nhSession.Get(instance.Id)
这样的东西。我的Delete<T>(T instance)
方法接收要删除的实体实例作为参数。它不会收到要删除的主键值。
有关详细信息,请参阅我的other问题。该问题讨论了UPDATE问题以及我如何修复它;但情况类似。
“@Ricardo Peres”的答案不起作用,但我修改了他的代码。
public static TEntity GetInstanceFromCache<TEntity>(this ISession nhSession, object instance) where TEntity : BaseEntity
{
var sessionImpl = nhSession.GetSessionImplementation();
foreach(BaseEntity baseEntity in sessionImpl.PersistenceContext.EntityEntries.Keys)
{
if(baseEntity is TEntity)
{
TEntity instanceFromCache = (TEntity)baseEntity;
if(nhSession.GetIdentifier(instanceFromCache) == nhSession.GetIdentifier(instance))
return baseEntity as TEntity;
}
}
return null;
}
调用nhSession.GetIdentifier(instance)
抛出异常TransientObjectException
(“实例未与此会话关联”),这是预期的。这是因为instance
未知nhSession
。获取与会话无关的实体标识符的任何方法吗?
答案 0 :(得分:2)
您需要掌握PersistenceContext,如下所示:
{{1}}
答案 1 :(得分:1)
使用“@Ricardo Peres”发布的代码,我能够解决它。但确切的代码不适用于我。我需要修改它,如下所示:
public static TEntity GetInstanceFromCache<TEntity>(this ISession nhSession, object instance) where TEntity : BaseEntity
{
object detachedIdentifier = GetDetachedEntityId<TEntity>(instance, nhSession.SessionFactory);
var sessionImpl = nhSession.GetSessionImplementation();
foreach(BaseEntity baseEntity in sessionImpl.PersistenceContext.EntityEntries.Keys)
{
if(baseEntity is TEntity)
{
TEntity instanceFromCache = (TEntity)baseEntity;
string idFromCache = Convert.ToString(nhSession.GetIdentifier(instanceFromCache));
string idNew = Convert.ToString(detachedIdentifier);
if(idFromCache == idNew)
return baseEntity as TEntity;
}
}
return null;
//Another way-----------------------------
//var entity = nhSession.GetSessionImplementation().PersistenceContext.EntitiesByKey.SingleOrDefault(x => x.Value is TEntity && Convert.ToString(x.Key.Identifier) == Convert.ToString(detachedIdentifier));
//return entity.Value as TEntity;
//Another way-----------------------------
}
public static object GetDetachedEntityId<TEntity>(object instance, ISessionFactory sessionFactory) where TEntity : BaseEntity
{
Type entityType = typeof(TEntity);
var entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor).TryGetEntityPersister(entityName) as AbstractEntityPersister;
if(persister != null)
{
PropertyInfo idPropertyInfo = entityType.GetProperty(persister.IdentifierPropertyName);
object identifier = idPropertyInfo.GetValue(instance, null);
return identifier;
}
return null;
}