3

データ管理コンソールとして機能する複数のページを持つ Web アプリがあります。DB に対してデータを検索したり、新しいエンティティを作成したり、編集、削除したりできます。これは、Razor を使用して ASP.NET MVC 3 で作成されます。

同じビューにアクセスするたびに、フォームの投稿データが「失われる」(適用されない) という問題があります。

バックグラウンド

サイト構造は、複数のビューを備えたかなり典型的なものです。1 つはホーム用、次に各エンティティ (親、子と呼びましょう) 用です。

  • 親要素を検索できる検索フィールドとしてのホーム ビュー。検索を送信すると、一致する親エンティティが HTML テーブルに表示されます。

ここに画像の説明を入力

  • HTML テーブルでは、各親行の横にアクションがあり、それを編集したり、子を表示したりします。をクリックするとShow Children、別のフォーム ポストが実行され、その親行の子が表示されます。例えば:

ここに画像の説明を入力

最初に、ホーム ビューで複数のフォームを使用してみsearchましparentchildren。ただし、これによりキャッシュに問題が発生しました-行の1つを編集することを選択したとき(対応するビューに移動してそれを行う)、ホームビューに送り返されたとき、以前の検索はまだ適用されていなかったので、検索を再開します。ページ全体で単一のフォームを保持すると、キャッシングが適切に機能することがわかりました。そのため、エンティティの編集に飛び込んだり外したりすると、キャッシングが機能しているように見えました (そして、全体的な使いやすさが向上しました)。

したがって、私が持っているコードはおおよそ次のとおりです(この質問のために単純化するために大幅に編集しました):

@using (Html.BeginForm("Index", "Home", FormMethod.Post ))
{
  <div>
    @Html.TextBoxFor(m => m.SearchTerm )
    <input type="submit" name="SearchSubmit" value="Search" />
  </div>
  <h2>Parents</h2>
  <div>
    @{
      var parents = Tool.Models.ToolsModelService.SearchParents(Model.SearchTerm);
    }
  </div>
  <div>
    <table>
        <thead>
           <tr>
             <th>Parent ID</th>
             <th>Attribute 1</th>
             <th>Attribute 2</th>
             <th>Actions</th>
           </tr>
        </thead>
        <tbody>
          @foreach (var p in parents)
          {
            <tr>
               <td>@p.ID</td>
               <td>@p.Name</td>
               <td>@p.Attrib1</td>
               <td>@p.Attrib2</td>
               <td>
                 <input type="hidden" name="SelectedParent" value="@p.ID.ToString()" />
                 <input type="submit" name="ParentSubmit" value="Edit" />
                 <input type="submit" name="ChildrenSubmit" value="Show Children" />
               </td>
            </tr>
           }
        </tbody>
     </table>
  </div>
  <div>
    <button type="submit" name="ParentSubmit" value="Add">Add New Parent</button>
  </div>
  @if (Model.SelectedParent != null)
  {
    var children = Tool.Models.ToolModelService.GetChildren(Model.SelectedParent);
    if (children != null && children.Count > 0)
    {
      <h2>Children</h2>
      <div>
        <table>
          <thead>
            <tr>
              <th>Child ID</th>
              <th>Name</th>
              <th>Action</th>
             </tr>
           </thead>
           <tbody>
           @foreach (var c in children)
           {
             <tr>
               <td>@c.ID</td>
               <td>@c.Name</td>
               <td>
               @using (Html.BeginForm("Index", "Home", FormMethod.Post))
               {
                  <input type="hidden" name="SelectedChild" value="@c.ID.ToString()" />
                  <input type="submit" name="ChildrenSubmit" value="Edit" />
               }
               </td>    
             </tr>
           }
           </tbody>
         </table>
       </div>
       <div>
         <input type="submit" name="MenuItemSubmit" value="Add">Add new child</button>
       </div>
    }
  }
  else
  {
    <h2>Children</h2>
    <div>
      <p>Select a parent to show children for<p>
    </div>
  }

HomeController.csは、たくさんのコードがあります。フォーム処理の一部を次に示します。

...

[Authorize]
public ActionResult Index(HomeModel model)
{
    model = new HomeModel();
    this.LoadState(model);
    return View(model);
}

[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
[AcceptParameter(Name = "SearchSubmit", Value = "Search")]
public ActionResult Register_Search(HomeModel model)
{
    ActionResult action;
    this.CacheState(model);
    action = this.View(model);
    return action;
}

[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
[AcceptParameter(Name = "ParentSubmit", Value = "Add")]
public ActionResult Register_ParentAdd(HomeModel model)
{
    this.CacheState(model);
    return this.RedirectToAction("Index", "Parent");
}

...

private void CacheState(HomeModel model)
{
    this.Session[CachedModelKey] = model;
}

private void LoadState(HomeModel model)
{
   if (null != this.Session[CachedModelKey])
   {
       var cachedModel = (HomeModel)this.Session[CachedModelKey];
       model.SearchTerm = cachedModel.SearchTerm;
       model.SelectedRestaurant = cachedModel.SelectedParent;
       model.SelectedMenuItem = cachedModel.SelectedChild;
   }
}

問題

私はさまざまな問題を抱えています.ASP.NET MVCに非常に慣れていないことと、コードですべてを適切に設定する方法が原因であると確信しています.

  1. parentsテーブル フォームが正しく機能しません。任意の行をクリックするShow childrenと、常に最初の行の子が表示されます。

  2. Parent1 を検索して子を選択し、子項目の 1 つ (別のビューにある) を編集する場合。最終的にホーム ビューに送り返されますが、検索は適用されなくなります。これが「キャッシュ」の意味です。すべての場合において、私のフォーム ポストの値は、ビューのリロード間で保持されません。

parent1ワークフローを遅くするものをもう一度検索する必要があります。私は本当に検索を永続化したいので、同じ子リストを表示するために再検索する必要はありません (同じ親に対して複数の子を編集し続けるのが簡単になります)

ここで何かが本当に簡単に欠けていると確信しているので、上記の問題を解決する助けをいただければ幸いです。また、物事を構造化するためのより良い方法についてのアドバイスもいただければ幸いです。情報が不足している場合はお知らせください。追加します。

4

1 に答える 1

1

このタイプのページを処理する良い方法は、Backbone.jsを使用することです。Backbone では、htmlテンプレートにバインドされたクライアント側のビューを設定できます。モデルデータをテンプレートにロードしてから、ビューをレンダリングします。

バックボーンモデルの変更をリッスンできるバックボーンビューでイベントを接続し、変更を示す適切なビューをレンダリングできます。

バックボーンには学習曲線がありますが、事前に作成された例から始めると、そのコツをつかむことができます。あなたのページにぴったりなので、学ぶ価値は間違いありません。

RobConeryはここで良い例を示しました... http: //wekeroad.com/2011/08/11/the-backbonejs-todo-list-sample-refactored-part-1/

キャッシュに関しては、ビューモデルオブジェクトをシリアル化可能にしてから、検索パラメーターから作成されたキーに対してSystem.Runtime.Caching.MemoryCacheを使用してオブジェクトをキャッシュします。これにより、データベースへの不必要な移動を回避できます。

于 2012-09-08T11:48:49.003 に答える