2017-06-12 59 views
3

我想对我发现,当我使用INSERT命令与NHibernate的无状态会话行为的意见(NB。我使用NHibernate的2.1.2)NHibernate的无国籍插入行为

的情况是这样的

//STATEFULL SESSION 
var session = sessionFactory.OpenSession() 
using(var transaction = session.BeginTransaction()){ 
    var entity = new MyEntityType(); 
    entity.Id = 1; 

    session.Save(entity); 

    var entity2 = session.Get<MyEntityType>(1); 
    //OK! It returns saved entity...as I expect 

    transaction.Commit(); 
} 

但是......对无状态会话,行为改变...

//STATELESS SESSION 
var session = sessionFactory.OpenStatelessSession() 
using(var transaction = session.BeginTransaction()){ 
    var entity = new MyEntityType(); 
    entity.Id = 1; 

    session.Insert(entity); 

    var entity2 = session.Get<MyEntityType>(1); 
    //entity2 IS NULL!!! Why? 

    transaction.Commit(); 
} 

我的问题是...我怎么能检查如果我已经插在无状态会话的事务范围的项目?

+0

请原谅我,但是您的应用程序是否实现了NHibernate具有的工作单元模式? –

回答

2

那么,无国籍是...无国籍。所以没有会话缓存让你插入的实体从内存返回。

现在,它为什么不读取数据库?因为它还没有在那里!

很有可能你已启用配料(adonet.batch_size XML配置参数,或通过代码Environment.BatchSize配置属性,或者没有通过IStatelessSession.SetBatchSize(int)禁用它,而它是在会话工厂级别启用)。启用批处理后,如果您的NHibernate数据库驱动程序支持它,则会尽可能将DML操作批处理到最大配置的批处理大小,然后刷新到数据库。

所以可能会出现一个无状态的会话这样的冲洗:达到

  • 如果“批量”操作,以执行计数。
  • 如果交易被提交。
  • 如果另一个DML查询不仅与其参数值有所不同,
    (对于您的情况,例如在插入后插入另一种实体,或在插入后更新或删除任何类型的实体)。
  • 通过明确刷新批处理器,轻击内部会话接口。
    s.GetSessionImplementation().Flush();

如果您希望您的Insert立即发送到数据库,禁用配料。将其设置为0将禁用它。

但为什么你首先使用无状态会话?可能以高性能的方式插入大量实体。在这种情况下,禁用批处理将会值得您的目的。

所以你可以改为通过会话GetSessionImplementation()方法暴露内部会话接口,并明确Flush它。但是,直接调用内部函数可能会产生未定义的行为,所以这不是推荐的做法。

+0

无状态会话不支持批处理IMO。调用'SetBatchSize()'方法会抛出异常。它是否正确? –

+0

不,它确实以有限的方式支持它,但确实如此。您可能会为整个会话工厂禁用配料。在这种情况下,会话工厂会为所有会话产生“NonBatchingBatcher”,并尝试在其上设置批量大小失败。事实上,'SetBatchSize'仅用于更改未禁用的批处理大小或禁用它。 –