我正在使用Session Per Presenter编写WPF NHibernate桌面应用程序。当您双击销售订单时,我有一个列表视图,显示所有已保存的SalesOrders和一个Edit Sales Order表单。
这些表单中的每一个都有一个会话对象,该对象在表单的生命周期内持续存在。保存SalesOrder时,它会发布一个事件,告诉列表视图重新加载。 EditForm肯定会保存到数据库中,ListView肯定是从数据库中选择的。但是,属于ListViewPresenter的会话不会使用从数据库中检索的实体更新其实体。它只返回与在保存任何内容之前首次加载listSession时相同的值。
下面是一些最能复制场景的代码: -
[Test]
public void SessionPerPresenter()
{
//This session is the one that is used to load all salesorders from the database. It's lifetime is the lifetime of the form but as you double click on an entry in the list to edit it will stay alive longer than the session in the edit form
ISession listSession = NHibernateHelper.OpenSession();
SalesOrder order = new SalesOrder("P123435", "ACME");
order.AddLine(new SalesOrderLine("Beans", 15));
order.AddLine(new SalesOrderLine("Coke", 24));
order.AddLine(new SalesOrderLine("Pepsi", 3));
order.AddLine(new SalesOrderLine("Apples", 4));
//this session is the equivalent of the one in the Edit Form as soon as the entity is Saved
//the session is disposed
using (ISession session = NHibernateHelper.OpenSession())
{
session.SaveOrUpdate(order);
ID = order.SalesOrderID;
}
//retrieve all SalesOrders from the database and store them in a list
IList<SalesOrder> salesOrders = listSession.CreateCriteria<SalesOrder>().List<SalesOrder>();
foreach (SalesOrder so in salesOrders)
{
Console.WriteLine(so.ToString());
}
//edit the selected order and update its order code value and resave
using (ISession session = NHibernateHelper.OpenSession())
{
hydratedSalesOrder = session.Get<SalesOrder>(ID);
hydratedSalesOrder.OrderCode = "1234-5678";
session.SaveOrUpdate(hydratedSalesOrder);
session.Flush();
}
//re-retrieve the list of orders from the database. Using SQLServer Profiler / NHibernate profiler
//you can see the query being sent to the database so I don't believe it is in the cache. Indeed, if you run
//the query directly against the database the value 1234-5678 is returned. Can't work out why
//the listSession does not have the values read from the database in it but has the values from the
//original list retrieval.
salesOrders = listSession.CreateCriteria<SalesOrder>().List<SalesOrder>();
foreach (SalesOrder so in salesOrders)
{
Console.WriteLine(so.ToString());
}
listSession.Close()
}
有人可以帮助我解决这里发生的事情吗?我究竟做错了什么?我错过了重要的事情吗?如果它没有查询数据库,我会认为这与第一级缓存有关,但这似乎不太可能。
答案 0 :(得分:0)
确保您的实体未被缓存的方法是使用ISession.Clear()
清除会话。您也可以通过调用ISession.Evict(object entity)
来驱逐单个实体。
如果您不确定应用程序中发生了什么,请考虑使用nhprof等分析工具。
快速说明:在没有并发问题的小型应用程序中使用会话可以很方便地使用会话的生命周期,但从长远来看,你会遇到麻烦。会话应该延迟开放,并提前关闭。