2012-12-22 58 views
1

我在Nhibernate 3中遇到了期货问题,无法识别出什么问题。Count +期货不能正常工作

下面的代码(不含期货),按预期工作:

SessionHandler.DoInTransaction(transaction => 
      { 
       var criteria = SessionHandler.Session.CreateCriteria<T>(); 
       var clonedCriteria = (ICriteria)criteria.Clone(); 

       var count = criteria 
        .SetProjection(Projections.RowCount()) 
        .UniqueResult<Int32>(); 


       var result = clonedCriteria 
        .SetMaxResults(PageSize) 
        .SetFirstResult(page * PageSize) 
        .List<T>(); 

       ItemList = result; 
       TotalResults = count; 
       RecalculatePageCount(); 
      }); 

SessionHandler只是存储此上下文的会话,并DoInTransaction是一个方便的方法:

public void DoInTransaction(Action<ITransaction> action) 
    { 
     using (var transaction = Session.BeginTransaction()) 
     { 

      action(transaction); 
      transaction.Commit(); 
     } 
    } 

现在,以下代码导致G​​enericAdoException:

SessionHandler.DoInTransaction(transaction => 
      { 
       var criteria = SessionHandler.Session.CreateCriteria<T>(); 
       var clonedCriteria = (ICriteria)criteria.Clone(); 

       var count = criteria 
        .SetProjection(Projections.RowCount()) 
        .FutureValue<Int32>(); 


       var result = clonedCriteria 
        .SetMaxResults(PageSize) 
        .SetFirstResult(page * PageSize) 
        .Future<T>(); 

       ItemList = result; 
       TotalResults = count.Value; 
       RecalculatePageCount(); 
      }); 

我正在使用PostgreSQL 9.2,Npgsql 2.0.11.0和NHibernate 3.3.1.4000。如果这很重要,我使用流利NHibernate的映射 谢谢你的任何建议。

编辑: 经过更多的研究,我发现这个错误只发生在我添加一个项目后。在开始时,我在我的表单中加载数据,它工作得很好。当我在添加项目后在表单中重新加载数据时,出现异常。但这很奇怪。该项目被正确添加。用于添加或更新项目的代码如下所示:

if (IsEditing) 
       { 
        SessionHandler.DoInTransaction(tx => SessionHandler.Session.Update(CurrentItem)); 
       } 
       else 
       { 
        SessionHandler.DoInTransaction(tx => SessionHandler.Session.Save(CurrentItem)); 
       } 

什么奇怪的是,我(有时候,我认为)让当我提高PropertyChanged事件此异常。我注意到有时候InnerException是不同的。听起来像是一个线程问题,但奇怪的是它没有未来。但我没有使用线程来加载数据,只是添加项目(嗯,但也许,因为我通知何时添加项目,并加载项目以回答“该消息”,我认为该负载将是在另一个线程执行)

编辑2: 错误似乎很随机。有时候我明白了,有时候不是:S

+0

什么是内部异常? GenericADOException只是NHibernate的全局数据库异常封装。 –

+0

我得到NotsupportedException:后端发送无法识别的响应类型:\ 0 我也在Npgsql中得到DataException –

+0

根据你的说法,使用踏步似乎令人怀疑。 –

回答

0

我想我已经找到了问题。

这听起来很愚蠢,但我认为它是有道理的。我只好换这些行:

ItemList = result; 
TotalResults = count.Value; 

所以他们造成

TotalResults = count.Value; 
ItemList = result; 

的问题,基本上,多线程(我想我没有提到它在我的问题相当多,但随机性错误有点可疑)。所以首先,我会告诉你一些背景,以便解决方案更清晰:

当一个新元素被添加到数据库中时,会发送一条消息(全局),所以每个人都有兴趣可以更新其元素以反映变化。由于我使用的MVVM光,我不喜欢这样写道:

Messenger.Default.Send(new DataReloadSuggested<MyEntityType>(theUpdatedId)); 

我用任务来添加元素,所以当我点击“添加”按钮,像这样被执行:

Task.Factory.StartNew(CommitCurrentItem); 

而且,在CommitCurrentItem中,我将该项添加到数据库并通知程序该列表已更新(如上所述发送消息)。注册的消息,像这样

我的主要形式有:

Messenger.Default.Register<DataReloadSuggested<T>>(this, true, unused => LoadPage(CurrentPage)); 

即使LoadPage功能没有(在那一刻)手动创建一个不同的线程,它在同一个线程执行的CommitCurrentItem 。任务不保证在不同的线程中运行,但在这种情况下是这样。 LoadPage只是调用了问题中的代码。我的代码保证会在UI线程中引发PropertyChanged事件(来自INotifyPropertyChanged接口),所以当我设置ItemList属性(IEnumerable类型)时,通知UI将显示新列表。因此,UI在(在另一个线程中)检索ItemList的新值时,行TotalResults = count.Value;正在执行。 在这种情况下,我猜这个查询不是针对数据库执行的,直到我检索到第一个值(列表中的第一项或RowCount)。 请记住,ISession不是线程安全的,所以这种情况不可靠:UI线程和另一个线程同时使用同一个会话。在我的代码中,我没有共享ViewModel之间的会话,并且每个ViewModel同时只使用一个线程的Session,以防止出现这种情况。

因此,最终的解决方案是强制在我工作的同一个线程中执行查询,所以我简单地在设置ItemListresult之前调用count.Value