计数+列表与期货不起作用

时间:2012-12-22 02:25:31

标签: c# wpf postgresql nhibernate

我在Nhibernate 3中遇到了Futures的问题,并且无法意识到什么是错的。

以下代码(没有期货)按预期工作:

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只存储此上下文的Session,而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。如果这很重要,我使用Fluent NHibernate作为我的映射 谢谢你的任何建议。

编辑: 经过更多的研究,我发现只有在添加项目后才会出现此错误。在开始时,我正在以我的形式加载数据,它工作得很好。我在添加项目后重新加载表单中的数据时出现异常。但这很奇怪。该项目已正确添加。添加或更新项目的代码如下所示:

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

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

编辑2: 这个错误似乎很随机。有时我得到它,有时不是:S

1 个答案:

答案 0 :(得分:0)

我想我已经找到了这个问题。

这可能听起来很愚蠢,但我认为这是有道理的。我不得不交换这些行:

ItemList = result;
TotalResults = count.Value;

所以他们结果

TotalResults = count.Value;
ItemList = result;

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

当一个新元素被添加到数据库时,一条消息被(全局)发送,所以每个人都感兴趣的#39;可以更新其元素以反映更改。当我使用MVVM Light时,我这样做:

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

我正在使用任务来添加元素,所以当我点击“添加&#39;按钮,这样的事情被执行了:

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只有一个线程,以防止出现这种情况。

所以,最终的解决方案是在我工作的同一个线程中强制执行查询,所以在将count.Value设置为ItemList之前我只需调用result