我正在研究一些需要更清晰的NHibernate的意外行为。 我创建一个新对象'Request'并保存它。我创建另一个对象'AuditLog'并添加请求作为对AuditLog的引用。我也保存了。 现在,如果Request对象被逐出会话(由于某种原因)并再次更新,则在提交事务时,AuditLog中的引用在数据库中是NULL化的。
关于为什么会发生这种情况的任何想法?
如果请求对象未在会话中创建,但是从数据库中检索,并且运行相同的进程,则会保留AuditLog中的引用。
为便于理解而编辑的示例代码。
如果我从代码中删除session.Evict(request1)
,则测试通过。使用此代码,当会话关闭时,会在DB上触发另一个查询,以使AuditLog中的请求引用为空。
//Session 1
var session = Resolve<IFullSession>().Session();
using (var tx = session.BeginTransaction())
{
var request1 = new Request { Id = "REQ01" };
request1.SetFieldValue("Type", "Stage1"); //Type is column in Request table
session.Save("Request", request1);
var auditLog1 = new AuditLog { Id = "LOG01" };
auditLog1.SetFieldValue("Request", request1); //Request is reference column to AuditLog
session.Save("AuditLog", auditLog1);
session.Evict(request1);
request1.SetFieldValue("Type", "Stage2");
session.SaveOrUpdate("Request", request1);
tx.Commit();
}
CreateInnerContainers(); // This closes earlier session.
//Session 2
var session2 = Resolve<IFullSession>().Session();
using (var tx = session2.BeginTransaction())
{
var theLogObject = session2.Get<AuditLog>("LOG01");
Assert.IsNotNull(theLogObject); // This is true
Assert.IsNotNull(theLogObject.GetFieldValue("Request")); // This fails
tx.Commit();
}
答案 0 :(得分:1)
您可以访问会话对象,然后使用您喜欢的任何内容
session.GetSessionImplementation().PersistenceContext.EntityEntries
but if I were you i would make sure that i'm evicting the right object and spend some time on debuging. Knowing what is going on is better than searching for workarounds
foreach (var e in session.GetSessionImplementation().PersistenceContext.EntityEntries.Values.OfType<EntityType>().Where(<condition>))
{
session.Evict(e);
}
答案 1 :(得分:1)
会话上的Save调用并不意味着您的实体被写入底层数据库。它将在当前持久化上下文(您的会话)中保持不变。
如果您现在从持久性上下文中删除此实体(您使用“evict”执行操作),则您的会话将无法将其保存在flush(事务结束)上。
尝试在session.Evict(request1)之前调用session.Flush(),看看会发生什么。
我不知道NHibernate,我来自hibernate,但最终这有助于澄清。