2016-07-21 5 views
2

私はASP.Net MVCアプリケーションを開発しており、データベースのデータを部分的なポストバックを介して更新しようとしているときにbizzareの問題に遭遇しています。私はHTTP、AJAXなどについてはまだまだ新しいので、明白な誤りだと思っています。ASP.NET MVC部分的なビューポストバック、一貫性のない更新とBizzareの動作

基本的に、コンテンツエリアと評価をリンクするテーブルを更新しようとすると、アップデートが動作することがあり、時にはそうではありません。 bizzareとは、私が投稿した後、MVCアプリケーションからデータベースに直接照会して、実際に期待される変更が行われたことを確認するだけです(これはViewBag.DebugInfoのすべてが以下のコードで行っています)。どんな場合でも、クエリは私が見たいものを返します。しかし、テーブルでSSMSを照会すると、時々変更が反映されることがあります。

私のMVCアプリケーションのテーブルへの直接クエリが、SSMS経由ではないことが明確にわかるうちに、更新が完了したことをどのように示していますか?静かなロールバックや何かがありますか?これは狂っていて、どんな助けでも大歓迎です。情報の

数ビット:私はMVCの外以下assessmentContentクラスから「saveTheData」機能を実行すると、それは常に成功する

  • 更新は最初の投稿では常に成功しています。
  • 更新は、後続の投稿の約半分に過ぎません。
  • 更新が成功しなかった場合でも、MVCアプリケーションからのダイレクトクエリのチェックでは、更新によってテーブルに移動したことが示されているようです。
  • 私は間違いなくパターンを作り出すことができます。つまり、より高いcontentId値に更新しようとするたびに成功します。より低いcontentIdに更新しようとすると、成功しません。たとえば、値1(Math)から2(Reading)への更新は常に行われますが、その逆は実行されません。このパターンは、親ビューからの最初の投稿であるか、Linqpad経由で更新されたものであるかを明示しません。
  • ログテーブルに書き込むデータベーステーブルにinsert、update、およびdeleteトリガーを挿入して、変更がロールバックされているかどうかを確認します。しかし、失敗したログテーブルのエントリはありません。しかし、ロールバックがトリガーも元に戻すかどうかはわかりません。
  • Operation = 'LOP_ABORT_XACT'のためにフィルタリングされたdbo.fn_dblog()を照会しましたが、何も表示されませんでした。私は私のMVCアプリケーションの外にそれを使用する場合

    public class assessmentContent { 
    
        public int? assessmentId { get; set; } 
        public List<short> baseline { get; set; } = new List<short>(); 
        public List<short> comparison { get; set; } = new List<short>(); 
    
        public assessmentContent() { if (assessmentId != null) refreshTheData(); } 
    
        public assessmentContent(int assessmentId) { 
         this.assessmentId = assessmentId; 
         refreshTheData(); 
        } 
    
        public void saveTheData() { 
    
         List<short> upserts = comparison.Except(baseline).ToList(); 
         List<short> deletes = baseline.Except(comparison).ToList(); 
    
         foreach (var upsert in upserts) 
          reval.ach.addAssessmentContent(assessmentId, upsert); 
    
         foreach (var delete in deletes) 
          reval.ach.deleteAssessmentContent(assessmentId, delete); 
    
         refreshTheData(); 
        } 
    
        void refreshTheData() { 
         baseline = reval.ach.assessmentContent(assessmentId).ToList(); 
         comparison = reval.ach.assessmentContent(assessmentId).ToList(); 
        } 
    
    } 
    

    ロジックが正常に動作します:

はここで取得し、データを更新私のクラスです。例えば、linqpad経由で使用する場合、問題はありません。 assessmentContent()に「getAssessmentContent()」という名前を付けることができます。私は3層アーキテクチャやモデル - ビュー - コントローラの構造は最高の実装がない可能性があることを承知している

public class ContentsModel { 
    public int? assessmentId { get; set; } 
    public List<short> comparison { get; set; } 
} 

public class ContentsController : Controller { 

    public static string nl = System.Environment.NewLine; 

    public ActionResult ContentsView(int assessmentId) { 

     ViewBag.DebugInfo = new List<string>(); 

     var vm = new ContentsModel(); 
     vm.assessmentId = assessmentId; 
     vm.comparison = reval.ach.assessmentContent(assessmentId).ToList(); 

     return View("~/Views/ach/Contents/ContentsView.cshtml", vm); 
    } 

    public ActionResult update(ContentsModel vm) { 

     ViewBag.DebugInfo = new List<string>(); 
     sqlFetch(); 

     ViewBag.DebugInfo.Add($"VM Pased In {vm.assessmentId} c{vm.comparison.intsJoin()}"); 
     sqlFetch(); 

     var crud = new crud.ach.assessmentContent((int)vm.assessmentId); 
     ViewBag.DebugInfo.Add($"newly fetched CRUD {crud.assessmentId} b{crud.baseline.intsJoin()} c{crud.comparison.intsJoin()}"); 
     sqlFetch(); 

     crud.comparison = vm.comparison; 
     ViewBag.DebugInfo.Add($"CRUD after crud_comparison = vm_comparison {crud.assessmentId} b{crud.baseline.intsJoin()} c{crud.comparison.intsJoin()}"); 
     sqlFetch(); 

     crud.saveTheData(); 
     ViewBag.DebugInfo.Add($"CRUD after save {crud.assessmentId} b{crud.baseline.intsJoin()} c{crud.comparison.intsJoin()}"); 
     sqlFetch(); 

     vm.comparison = crud.comparison; 
     ViewBag.DebugInfo.Add($"VM after vm_comparison = crud_comparison {vm.assessmentId} c{vm.comparison.intsJoin()}"); 
     sqlFetch(); 

     return PartialView("~/Views/ach/Contents/ContentsView.cshtml", vm); 
    } 

    void sqlFetch() { 
     ViewBag.DebugInfo.Add(
       "SQL Fetch " + 
       Sql.ExecuteOneColumn<short>("select contentId from ach.assessmentContent where assessmentId = 12", connections.research).intsJoin() 
      ); 
    } 

} 

public static partial class extensions { 

    public static string intsJoin(this IEnumerable<short> ints) { 

     var strings = new List<string>(); 
     foreach (int i in ints) 
      strings.Add(i.ToString()); 
     return string.Join(",", strings); 
    } 

} 

は、ここに私の部分図のためのコントローラ、およびいくつかの関連するコードですここに。

モデルの変更点ごとにデータベーステーブルに直接チェックしました。

部分図:

@model reval.Views.ach.Contents.ContentsModel 
@using reval 
@{Layout = "";} 

<div id="contentDiv"> 

    <form id="contentForm"> 

     @Html.HiddenFor(m => m.assessmentId) 

     @Html.ListBoxFor(
      m => m.comparison, 
      new reval.ach.content() 
       .GetEnumInfo() 
       .toMultiSelectList(
        v => v.Value, 
        d => d.DisplayName ?? d.Description ?? d.Name, 
        s => Model.comparison.Contains((short)s.Value) 
       ), 
      new { id = "contentListBox" } 
     ) 

    </form> 

    <br/> 
    @foreach(string di in ViewBag.DebugInfo) { 
     @Html.Label(di) 
     <br/> 
    } 

</div> 

<script> 

    $("#contentListBox").change(function() { 

     $.ajax({ 

      url: "/Contents/update", 
      type: "get", 
      data: $("#contentForm").serialize(), 
      success: function (result) { 
       $("#contentDiv").html(result); 
      }, 
      error: function (request, status, error) { 
       var wnd = window.open("about:blank", "", "_blank"); 
       wnd.document.write(request.responseText); 
      } 
     }); 
    }) 

</script> 

そして最後に、メインビューからの呼び出し:

<div id="testDiv"> 
@if (Model.assessment != null && Model.assessment.assessmentId != null) { 

    Html.RenderAction("ContentsView", "Contents", new { assessmentId = Model.assessment.assessmentId }); 

} 
</div> 

答えて

1

問題を解決するときに、私が解決したことを正確に突き止めることなくそれを嫌うのは嫌です。しかし、上のコードのいくつかを試した後、私はそれが正しく、一貫して動作するようにしました。

しかし、ほとんどの問題は、asp.net mvcがサーバーからクライアントにデータを渡して戻ってきたときの誤解と関係していたことは確かです。つまり、クライアントのhtml/aspにデータが送信されたときに、サーバーのC#ビューモデルとコントローラがまだ生きていたという考えがありました。私は、クライアントデータがC#オブジェクトと同じではないことに気付きましたが、ASP.Net MVCがポストバックの変更についてC#オブジェクトを更新していると感じました。現在、C#オブジェクトは完全に破棄され、完全にインスタンス化され(コンストラクタが呼び出され、関連するすべての結果が生じる)、クライアントからのデータが再投入されることは明らかです。クライアントで変更が加えられていなくても、これは当てはまります。

実際に更新がデータベースに行われたと思います。ロールバックは発生していませんでした。しかし、データベースへの2回目の呼び出しとその値のリセットを引き起こしていた再インスタンス化時に何かが起こっていました。これは、なぜASP.net MVCの外部で完全に動作していたのかを説明します。なぜこの実現後に私が問題を解決したのかを説明します。

この回答は正確ではありますが、正確ではありません。これにより、上の問題コードの正確な行を特定しなくても、ガイダンスが問題を解決するという確信が得られます。正確さのために、私はそれを答えとしてマークする公正ゲームと考えています。不正確さのために、私は、他の人の回答をより正確にすることができれば答えとしてマークすることができます。しかし、上のコードはもはや使用されていないので、学習目的のためだけです。

1

はあなたがデータベースに作っているトランザクションがコミットされていることを確認していますまたはファイナライズ?あなたが作っているものをロールバックすることができる他のトランザクションが同時に起こっている可能性があります。

+0

私は間違いなく確信していますが、同時に私はトランザクションの問題が疑いのある唯一の理由は、症状のためだと言うでしょう。私はトランザクションに関係する明示的なコードを書いていません。私の答えで言及された私の試みを除いて、あなたが私がどのようにトラブルシューティングするかに関するアドバイスがあれば教えてください。ありがとう。 – pwilcox

+0

さて、あなたは私を正しい道のりに置いたと思う。私が安心して言うのは早いですが、明示的なトランザクションを追加し、基礎となるデータアクセスコードにコミットすることで問題を解決できたかもしれません。そうでない場合でも、似たような問題を抱えている興味のあるユーザーにとっては、問題の可能性を検討することが重要です。実際に私が解決策を持っているなら、私は返信します。ありがとうございました!!!。 – pwilcox

+0

私はそれが問題ではないようであることを報告することを後悔します。さらに、上記の障害の順序パターンは保持されていないようです。 – pwilcox

関連する問題