1

Nhibernate 3のFuturesに問題があり、何が問題なのかわかりません。

次のコード(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は、このコンテキストのセッションを格納するだけであり、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、NHibernate3.3.1.4000を使用しています。それが重要な場合は、マッピングにFluentNHibernateを使用します。アドバイスをありがとうございます。

編集:さらに調査した結果、このエラーはアイテムを追加した後にのみ発生することがわかりました。開始時に、フォームにデータを読み込んでいますが、問題なく機能します。アイテムを追加した後にフォームにデータをリロードすると、例外が発生します。しかし、それはかなり奇妙です。アイテムが正しく追加されます。アイテムを追加または更新するためのコードは次のようになります。

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

奇妙なことに、PropertyChangedイベントを発生させているときに、この例外が発生することがあります(時々、私は思います)。InnerExceptionが異なる場合があることに気づきました。スレッドの問題のように聞こえますが、先物なしで機能するのは奇妙です。しかし、私はデータをロードするためにスレッドを使用していません。アイテムを追加するためだけです(うーん、でも、アイテムが追加されたときに通知し、「そのメッセージ」に応答してアイテムをロードするため、ロードは別のスレッドで実行)

編集2:エラーはかなりランダムに見えます。時々私はそれを得る、時にはそうではない:S

4

1 に答える 1

0

私は問題を見つけたと思います。

これはばかげているように聞こえるかもしれませんが、理にかなっていると思います。これらの行を交換する必要がありました:

ItemList = result;
TotalResults = count.Value;

だから彼らは結果として

TotalResults = count.Value;
ItemList = result;

問題は、基本的にはマルチスレッドでした (私の質問ではあまり触れていなかったと思いますが、エラーのランダム性は少し疑わしいものでした)。最初に、解決策がより明確になるように背景を説明します。

新しい要素がデータベースに追加されると、メッセージが (グローバルに) 送信されるため、「関心のある」すべてのユーザーがその要素を更新して変更を反映できます。MVVM Light を使用しているので、次のようにします。

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

Tasks を使用して要素を追加していたので、[追加] ボタンをクリックすると、次のようなものが実行されました。

Task.Factory.StartNew(CommitCurrentItem);

そして、CommitCurrentItem 内で、アイテムをデータベースに追加し、リストが更新されたことをプログラムに通知します (上記のメッセージを送信します)。

次のように、そのメッセージに登録された私のメインフォーム:

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

LoadPage 関数は (その時点で) 別のスレッドを手動で作成していませんでしたが、CommitCurrentItem と同じスレッドで実行されました。Task が別のスレッドで実行されることは保証されていませんが、この場合はそうでした。LoadPage は問題のコードを呼び出しました。私のコードは、UI スレッドで (INotifyPropertyChanged インターフェイスから) PropertyChanged イベントを発生させることが保証されているため、(IEnumerable 型の) ItemList プロパティを設定すると、UI に通知され、新しいリストが表示されます。そのため、UI は ItemList の新しい値を取得しましたが、(他のスレッドで) 行TotalResults = count.Value;実行していました。この場合、最初の値 (リストの最初の項目または RowCount) を取得するまで、クエリはデータベースに対して実行されないと思います。ISession はスレッド セーフではないため、この状況は信頼できませんでした。UI スレッドと他のスレッドが同じセッションを同時に使用していました。私のコードでは、ViewModel 間でセッションを共有していません。この種の状況を防ぐために、各 ViewModel は同時に 1 つのスレッドのみで Session を使用します。

したがって、最終的な解決策は、作業中の同じスレッドでクエリの実行を強制することだったので、count.Valueに設定ItemListする前に単純に呼び出しましたresult

于 2012-12-23T23:17:39.893 に答える