nhibernate应该在“SaveOrUpdate”之后显式刷新会话吗?

时间:2010-01-14 17:57:00

标签: nhibernate session

我写了一个失败的集成测试:

    [Test]
    public void Find_WorkItemWithMatchingDescriptionExistsInRepository_ReturnsWorkItem()
    {
        // arrange
        WorkItemRepository repository = new WorkItemRepository(IsolatingFactory);

        const string Description = "A";
        WorkItem itemWithMatchingDescription = WorkItem.Create(1, Description);
        repository.Commit(itemWithMatchingDescription);

        // act
        List<WorkItem> searchResult = repository.Find(Description);

        // assert
        CollectionAssert.Contains(searchResult, itemWithMatchingDescription);
    }

当观察来自nhibernate的sql输出时,我注意到它为repository.Find()操作创建了一个select语句,但是在select之前没有插入操作。如果我在repository.Commit之后放置一个显式session.Flush()它按预期工作,但我觉得这个行为很奇怪。为什么当有挂起的插入并且对会话执行查询时,nhibernate不会自动刷新会话?

我在文档中找到了这个:

9.6。冲洗

  

ISession将不时执行将ADO.NET连接状态与内存中保存的对象状态同步所需的SQL语句。默认情况下,此过程刷新,发生在以下几点

* from some invocations of Find() or Enumerable()
* from NHibernate.ITransaction.Commit()
* from ISession.Flush() 

看起来默认的nhibernate行为是在通过find查询之前刷新。我的存储库使用Ling来查询规范的nhibernate,也许这是一个错误。

更新

如果我改变了我的映射:

    public WorkItemClassMap()
    {
        Not.LazyLoad();

        Id(wi => wi.Id).GeneratedBy.Assigned();
        Map(wi => wi.Description).Length(500);
        Version(wi => wi.LastChanged).UnsavedValue(new DateTime().ToString());
    }

要:

    public WorkItemClassMap()
    {
        Not.LazyLoad();

        Id(wi => wi.Id).GeneratedBy.Identity();
        Map(wi => wi.Description).Length(500);
    }

它按预期工作(nhibernate在执行查询之前将插入刷新到数据库)。我看不出这种行为的任何正当理由,所以我假设它有一个bug。看起来需要在我的存储库中查询之前进行手动刷新,这不是我真正想做的事情。

3 个答案:

答案 0 :(得分:3)

您应该为insert和select方法使用不同的ISession实例。最好是这些会话位于using块中,以便它们在数据库事务中被妥善处理:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    // perform your insert here
    tx.Commit();
}

答案 1 :(得分:2)

您的示例中的WorkItem是否使用复合ID进行映射?我只编了一个简单的测试。当我有一个标识列时,我的虚拟类会自动刷新。我使用复合ID编写了相同的测试,但我得到了您在上面描述的行为。

答案 2 :(得分:0)

假设您的存储库创建或接受已存在的会话。当您创建WorkItem并提交它时,它只会继续执行该会话的作业列表。如果您的存储库没有创建事务,并且您的提交方法没有明确提交事务。然后更新或保存将等到会话关闭,因此尽管您可以看到您创建的对象,但是在关闭会话或刷新会话之前,您将无法获得范围标识。当然,如果没有刷新或关闭事务,searchResult将不会知道您创建的对象。

一般情况下,事务与会话相同,但是如果要创建新对象,则应使用显式事务。 NHProfiler会随时警告你。