2017-03-03 3 views
1

私は現在、古いWindowsアプリケーションを修正しており、Hibernateエラーが発生しました。私はネットでいくつかのことを読んで試しましたが、最終的にエラーに終わりました。ここでNHibernate SaveOrUpdateエラー

はISessionのために私のコードです:ここでは

Public ReadOnly Property session() As ISession 
    Get 
     If IsNothing(m_session) Then 
      m_session = Factory.InitConfiguration.OpenSession() 
     End If 
     Return m_session 
    End Get 
End Property 

は、保存ボタンのための私のコードです:

 Try 
      session.BeginTransaction() 
      SetParent(x_object) 
      'session.clear() 
      session.Flush() 
      session.SaveOrUpdate(x_object) 
      session.Transaction.Commit() 
      compObj.IsNew = False 
      Return True 
    Catch ex As Exception 
     AppServices.ErrorMessage = ex.Message 
     session.Transaction.Rollback() 
     Return False 
    Finally 
     'TBA 
    End Try 

ので、問題はここから始め、私は日時とAttachmentListとしてこの日付列を持っています。

今年のユーザーキーが1753未満になるまで、現在のコードは問題ありません。しかし、コードはエラーを正しくキャッチしてメッセージを表示し、ユーザーが年年のタイプミスを修正し続けると、ユーザーがアプリケーションを閉じてから再び開くまで、エラーをキャッチしています(ウォッチでは新しい値を取得しています)。

しかし、私がsession.clear()のコメントを外してしまえば、ユーザーは入力ミスを修正してレコードを保存し続けることができますが、ユーザーが別のアクションを実行すると、エラー。以下のようにアタッチメントアクション:

  1. は添付
  2. を追加し、[保存]ボタン
  3. は、保存ボタン
  4. 新しいエラーをクリックして新しい添付
  5. の追加]をクリックします。

    enter image description here

だから行われるために必要なものの上に私をアドバイスをしてください。私はマージを試みました、私は更新を試みました、保存して、エビクトが、エラーを終了します。私は自分の問題は、私がどのようにセッションを整理するのが問題の主な原因だと思う。

+0

'm_session'と' x_object'の範囲は何ですか?エンティティをDTOのよ​​うなものにマッピングしていますか? –

+0

@A_Jはいエンティティを多くの子にマッピングし、1つの親として設定しています。しかし、私の問題はフレデリックの説明によって解決されます。あなたは理由を紹介するかもしれません。 –

答えて

0

処理が必要なコードのように、失敗したフラッシュまたはトランザクションコミットを経験したセッションを使用しようとしているようです。

これは反パターンです。 NHibernate referenceから:

NHibernateを使用すると、通常はHibernateExceptionが発生する可能性があります。 この例外にはネストされた内部例外(根本原因)があり、 InnerExceptionプロパティを使用してアクセスします。

ISessionで例外がスローされた場合は、即座にトランザクション をロールバックし、ISession.Close()を呼び出してISession インスタンスを破棄する必要があります。セッションの特定のメソッドは、セッションを の一貫した状態にしません。

...

次の例外処理イディオムは、NHibernateのアプリケーションで典型的なケースを示しています

using (ISession sess = factory.OpenSession()) 
using (ITransaction tx = sess.BeginTransaction()) 
{ 
    // do some work 
    ... 
    tx.Commit(); 
} 

または、手動でADO.NETのトランザクションを管理:

ISession sess = factory.openSession(); 
try 
{ 
    // do some work 
    ... 
    sess.Flush(); 
    currentTransaction.Commit(); 
} 
catch (Exception e) 
{ 
    currentTransaction.Rollback(); 
    throw; 
} 
finally 
{ 
    sess.Close(); 
} 

あなた例外の後でコードがセッションを使用し続けるようにしないようにする必要があります。

さらに、ユーザーのやりとりを待っている間にセッションが開いたままになっているように見えます。これはお勧めのパターンではありません。 NHibernateセッションは通常は短命です。セッションを開くのは安いです。

通常のパターンは、ユーザがコーヒーを飲みながら開いたままにしないために、イベントを処理する前にユーザ入力からイベントを処理して終了するときに開きます。

特に、アプリケーションがエンティティへの参照を保持していて、ユーザーとのやりとりを待って開いたセッションに依然としてバインドされていることが予想される場合は、アプリケーションセッション管理を変更するのが難しい場合があります。

「最初のレベルのキャッシュを利用する」(セッションエンティティキャッシュ)のためにユーザー対話の間に開かれたセッションを維持する選択肢がある場合は、代わりに第2レベルのキャッシュをアクティブ化することを検討してください。

+0

私はあなたの説明から最終的に理解し、私の問題を解決しました。あなたの説明は解決策を見つけるのに役立ちますが、コードロジックを使ってオブジェクトにSaveOrUpdateCopyを使用することになります。今度はこの古い方法を新しいものに変更する時期です。あなたの説明のためにおかげでおかげで! –

0

あなたのm_sessionx_objectオブジェクトの範囲については言及していません。また、あなたはエンティティをどのように扱っているかについて言及していません。エンティティをDTOのよ​​うなものにマッピングしていますか?

をこれが第1レベル(セッション)キャッシュによる起こることがあります。

が、これはなぜ起こるか私たちは見てみましょう。エンティティSaveOrUpdateを試してみてください。間違ったデータが原因で失敗します。しかし、エンティティはまだセッションキャッシュにあります。その後、ユーザーは間違いを訂正し、再度保存します。すでにセッション中のエンティティと競合するエンティティNEWでもう一度SaveOrUpdateを実行します。両方のエンティティの識別子は同じです。

thisthisを参照してください。

session.clear()のコメントを外すと、最初のエンティティがセッションから離れ、新しいエンティティが正しく動作します。

上記のリンクもclear()の代わりにこのシナリオを処理する方法を提案しています。

Clear私の理解には良い解決策ではありません。セッション全体がクリアされます。 Evictが良い選択肢です。Evictがあなたのために働いていない場合、あなたは正しいインスタンスを払っていないかもしれません。

以下はC#コードです。あなたはVB.NETにそれを翻訳する必要があります - あなたは、私は上記のリンクのいずれかからGetInstanceFromCache方法を得ることができます

try 
{ 
    nhSession.SaveOrUpdate(instance); 
} 
catch(NonUniqueObjectException) 
{ 
    T instanceFromCache = GetInstanceFromCache<T>(instance); 
    nhSession.Evict(instanceFromCache); 
    nhSession.SaveOrUpdate(instance); 
} 

+1

あなたの方法は私にとってはうまくいくが、少し遅くなり、他のタブで新しい問題が発生する。しかし、私の問題はSaveorupdatecopyを使って@Frederic投稿からの答えに基づいて解決されています。あなたの説明のために多くのおかげでありがとう、私は今NHibernateについてこれを新たに探究することを理解する。 –

関連する問題