none
オブジェクトインスタンスがforループの途中で破棄される事がある RRS feed

  • 質問

  • お世話になります。ご教示ください。

    (※質問したいソースがvb.netの為、こちらにて質問をさせていただきますが、

    フォーラムカテゴリ間違いでしたら、ご指摘ください)

    MVC5の考え方を利用し、AzureDbを利用したWEBシステムを開発しています。

    for each内に、AzureのDBにアクセスし、Updateをしている箇所があります。

    すると、極たまにオブジェクトインスタンスが破棄されてしまいます。

    下記ソースに何か問題はありますでしょうか。

    手順を含めて記載します。

    1.HTML上で送信ボタンを押す

    2.コントローラで処理を振り分ける

    3.処理をする

            Using tx = _db.Database.BeginTransaction ←_dbはスキャフォールディングで作成されたdbcontextをnewしたもの
                Try

                    For Each item In value.ResultModel.ShoninList ←画面にあるリスト
                        If item.Check = True Then ←チェックボックス入れてあるもののみ処理
                            Call ComShonin.ShoninProc(_db,PAY_NO, loginSyainId) ←承認処理
                        End If
                    Next

                    Call tx.Commit()

                    Return True
                Catch ex As Exception
                    'ロールバック
                    Call tx.Rollback()
                    Return False
                End Try
            End Using

        Public Shared Sub ShoninProc(db As DbContext, payNo As String, shoninSyainId As String)

                With Nothing
                    Dim tShoninRoute = eShoninRoute.Where(Function(m) m.SHONIN_NO = 0 AndAlso Not m.SHONIN_DATE.HasValue AndAlso String.IsNullOrWhiteSpace(m.SHONIN_SYAINID)).First

                    With tShoninRoute
                        .SHONIN_SYAINID = shoninSyainId
                        .SHONIN_DATE = dShoninDate
                    End With
                    Call RepShoninRoute.Save() ←この中で _db.SaveChanges()を行うがここで落ちる時がある。その際の画面のエラーメッセージはオブジェクトインスタンスが破棄されているため~ というもの

                End With

        End Sub

    この破棄が何故起きるのかがわからず困っております。

    例えば、画面に20項目あって、15項目にチェックを入れボタンを押した場合

    12件目までは1秒以内に処理が終わっているのに突如破棄されてしまい、その後タイムアウトに引っかかってしまう。という

    事があります。

    尚、テストは自分ひとりで行っています。

    何かお気づきの点とかあれば些細なことでも結構ですので、教えていただければ幸いです。

    2017年4月26日 1:06

すべての返信

  • コードの詳細内容が不明なので単なる想像ですが・・・

    > Catch ex As Exception

    Exception を catch しているので例外が発生してもなかったことになってしまうということが怪しそうな気がします。

    一般的に、Exception をキャッチするのは止めた方がいいです。理由は以下の記事を見てください。

    NETの例外処理 Part.1
    https://blogs.msdn.microsoft.com/nakama/2008/12/29/net-part-1/

    .NETの例外処理 Part.2
    https://blogs.msdn.microsoft.com/nakama/2009/01/02/net-part-2/

    .NET 4 からは破損状態例外は catch できなくなっているそうですが、「それでも Catch (Exception e) を使用するのはよくない」ということについては以下の記事を見てください。

    破損状態例外を処理する
    https://msdn.microsoft.com/ja-jp/magazine/dd419661.aspx

    質問者さんのコードではロールバックするために Exception を catch しているようですが、ロールバックしたら即例外を再スローしたらどうなりますか?

    具体例は、上に紹介した記事「.NETの例外処理 Part.2」の[トランザクション処理を伴うときの try ブロックの記述]のセクションを見てください。


    最初に書きましたが単なる想像ですので、Exception をキャッチは今回の問題の原因としてはハズレかもしれません。ただし、Exception をキャッチするのは止めた方がいいのは確かなようですので、それが原因ではなくても直した方がよさそうです。

    2017年4月26日 1:57
  • 12件目までは1秒以内というのは、トータル1秒以内ということでしょうか?

    あるいは1件当たり1秒以内で、トータルでは10秒とか(細かい数値はいいですが)、そんなイメージでしょうか?

    エラーメッセージがわかるということは、Catch句で、実際には例外内容を保存するなり画面出力できるようにするなりしているということでしょうか?

    処理時間的には違いそうもな気もしますが、たとえばAzureDBの接続は30秒とかで自動切断されたと思いますが、そのあたりは大丈夫でしょうか?

    --追記

    DBの自動切断は、アイドル時間30分とかですね、これはちょっと違いますね。


    • 編集済み なちゃ 2017年4月26日 5:14
    2017年4月26日 5:11
  • お忙しい中お返事をいただきありがとうございます。

    try catchの件は使い方を誤っているようで、ご教示いただいたページを参考にさせていただきます。

    内容がとても濃く、流し読みではとても理解が困難ですので、

    こちらは勉強していきたいと思います。

    本件に関係あるなしに関わらず、有益な情報をありがとうございます。

    取り合えず、事象の再現性が薄いため、スローにした後にまだ同一事象が発生しておりません。

    進展いたしましたら、また投稿いたします。

    2017年4月26日 5:37
  • お忙しいなかお返事をありがとうございます。

    >>12件目までは1秒以内というのは、トータル1秒以内ということでしょうか?

    UPDATEをするたびに、更新日時をnowで保存しておりますが、10件で1秒ぐらいです。

    エラーメッセージは、上手く説明出来ないのですが、エラーになった時に

    @ModelType System.Web.Mvc.HandleErrorInfo

    より

    <table class="table">
        <tr>
            <th>発生元</th>
            <td>@Model.ControllerName / @Model.ActionName</td>
        </tr>
        <tr>
            <th>例外</th>
            <td>@Model.Exception.GetType().Name</td>
        </tr>
        <tr>
            <th>メッセージ</th>
            <td>@Model.Exception.Message</td>
        </tr>
    </table>

    こうすると、つかめるとどこかの情報サイトより見つけ、利用しております。

    また仰るとおり、AZUREDBの接続は30秒(どこで設定しているのかが検索してもみつからない・・・)

    ぐらいで切れるのは確認しております。

    その場合、オブジェクトインスタンスのエラーではなく、タイムアウトというエラーに変わります。

    (後だしになって大変申し訳ありません、極稀にタイムアウトの場合もあるのです。)

    何かの切り分けになるかもしれませんので、エラーの一文を貼り付けます。

    ○オブジェクトインスタンスの設定エラーの場合

    System.NullReferenceException: Object reference not set to an instance of an object.

    ○タイムアウトの場合

    System.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired.

    いずれも確実な再現ができません。偶然おきるまで繰り返ししている次第です。

    2017年4月26日 5:49
  • お世話になります。

    あれから気づいた事や誤っていることをいくつか発見しましたので

    フィードバックの為に、記載します。

    オブジェクトインスタンスが破棄されている、のメッセージは、

    正確には、オブジェクトDBコンテキストの破棄でした。

    このDBコンテキストの宣言の仕方が曖昧でしたのが一つ問題だったのかなと考えています。

    [宣言部]

        Private _db As New SampleDbContext
        Private _RepA As A_Repository
        Private _RepB As B_Repository
        Private _RepC As C_Repository

            _RepA = New A_Repository(_db)
            _RepB = New B_Repository(_db)
            _RepC = New C_Repository(_db)

          

    【呼び出し部抜粋】

      Using tx = _db.Database.BeginTransaction

         call shonin(_db)

     End Using

    Public Shared Sub shonin(_db As SampleDbContext)

            Dim _RepA = A_Repository(_db)
            Dim _RepB = B_Repository(_db)
            Dim _RepC = C_Repository(_db)

    RepA で処理

    RepBで処理 ←この当たりで 破棄されているメッセージで落ちる時がある

    end sub

    repositoryで、インタフェースを呼び出し、Inherits IDisposableを実装

    この当たりのどこかで、解放が誤って走っているのではないかと思っています。

    いずれにしても、当初の質問やタイトルからはずれてきてしまっていますので

    一旦こちらは閉じたいと思います。

    ご協力ありがとうございました。

    2017年4月28日 2:00