计数+列表与期货不工作

本文关键字:工作 列表 计数 | 更新日期: 2023-09-27 17:49:19

我在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();
        }
    }

现在,下面的代码导致GenericAdoException:

    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

计数+列表与期货不工作

我想我找到问题了。

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

ItemList = result;
TotalResults = count.Value;

所以他们得出

TotalResults = count.Value;
ItemList = result;

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

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

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在(在另一个线程中)执行TotalResults = count.Value;时检索ItemList的新值。在本例中,我猜在检索到第一个值(列表或RowCount中的第一项)之前不会对数据库执行查询。请记住,session不是线程安全的,所以这种情况是不可靠的:UI线程和另一个线程在同一时间使用同一个会话。在我的代码中,我没有在ViewModel之间共享会话,并且每个ViewModel同时只使用一个线程的会话,以防止这种情况。

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