web-dev-qa-db-ja.com

Entity Framework(.edmxモデル)とRazorビューを使用してMVC3のドロップダウンリストを作成&&データベースレコードを複数のテーブルに挿入

Razorビューを使用してMVC 3でドロップダウンリストを作成する方法についての記事を何百も読んだ後、自分のケースに合ったものが見つかりませんでした。

状況:最終的には、従業員をデータベースに追加するためのビューを作成しようとしています。

これは、私が使用している.EDMXモデルのイメージです(create()で使用されるテーブル)。

enter image description here

目的:

  1. 従業員を作成します(StaffNotifyチェックボックスの部分ビューで作成されたCreate.cshtml(厳密に型指定されています)){CreateビューからのNotify部分ビューで別の@modelを使用していますが、それが安全かどうかわかりませんか? @model ShadowVenue.Models.Employeeおよび@model ShadowVenue.Models.StaffNotify)

  2. StaffTypeIdのドロップダウンボックスを作成します(テーブル "StaffType"(1対多の関係)から[StaffTypeId]値を挿入しますが、ドロップダウンに[Type]文字列値を表示します)

  3. GenderIdのドロップダウンボックスを作成します(テーブル "Genders"(1対多の関係)から[GenderId]値を挿入しますが、ドロップダウンに[Gender]文字列値を表示します)

  4. データベースにレコードを挿入します(StaffIdプライマリキーに1対1の関係を持つ別のテーブルにスタッフ通知があります)

私はこのためのコントローラーコードに問題があるようです。

EDMXモデル内にストアドプロシージャを作成する必要があるのか​​、クエリまたはメソッドの構文を作成するのかはわかりませんが、どちらが最善の方法かわかりません。

これは、Entity Framework Modelを使用した初めての大規模MVC3アプリです。

(ソリューションを支援するためにナビゲーションプロパティ名のいずれかを知る必要がある場合はお知らせください)、提供します)

49
Timothy Green

Dbモデルをビューに直接渡さないでください。 MVCを使用できて幸運なので、ビューモデルを使用してカプセル化します。

次のようなビューモデルクラスを作成します。

public class EmployeeAddViewModel
{
    public Employee employee { get; set; }
    public Dictionary<int, string> staffTypes { get; set; }
    // really? a 1-to-many for genders
    public Dictionary<int, string> genderTypes { get; set; }

    public EmployeeAddViewModel() { }
    public EmployeeAddViewModel(int id)
    {
        employee = someEntityContext.Employees
            .Where(e => e.ID == id).SingleOrDefault();

        // instantiate your dictionaries

        foreach(var staffType in someEntityContext.StaffTypes)
        {
            staffTypes.Add(staffType.ID, staffType.Type);
        }

        // repeat similar loop for gender types
    }
}

コントローラ:

[HttpGet]
public ActionResult Add()
{
    return View(new EmployeeAddViewModel());
}

[HttpPost]
public ActionResult Add(EmployeeAddViewModel vm)
{
    if(ModelState.IsValid)
    {
        Employee.Add(vm.Employee);
        return View("Index"); // or wherever you go after successful add
    }

    return View(vm);
}

次に、最後にビューで(Visual Studioを使用して最初にスキャフォールドできます)、継承された型をShadowVenue.Models.EmployeeAddViewModelに変更します。また、ドロップダウンリストの場所では、次を使用します。

@Html.DropDownListFor(model => model.employee.staffTypeID,
    new SelectList(model.staffTypes, "ID", "Type"))

性別のドロップダウンでも同様です

@Html.DropDownListFor(model => model.employee.genderID,
    new SelectList(model.genderTypes, "ID", "Gender"))

コメントごとに更新

性別については、上記の推奨ビューモデルでgenderTypesがなくてもかまいません(ただし、考え直して、このサーバー側をビューモデルでIEnumerableとして生成することもできます)。したがって、以下のnew SelectList...の代わりに、IEnumerableを使用します。

@Html.DropDownListFor(model => model.employee.genderID,
    new SelectList(new SelectList()
    {
        new { ID = 1, Gender = "Male" },
        new { ID = 2, Gender = "Female" }
    }, "ID", "Gender"))

最後に、別のオプションはルックアップテーブルです。基本的に、ルックアップタイプに関連付けられたキーと値のペアを保持します。タイプの1つの例としては性別、別の例としては州などが考えられます。

ID | LookupType | LookupKey | LookupValue | LookupDescription | Active
1  | Gender     | 1         | Male        | male gender       | 1
2  | State      | 50        | Hawaii      | 50th state        | 1
3  | Gender     | 2         | Female      | female gender     | 1
4  | State      | 49        | Alaska      | 49th state        | 1
5  | OrderType  | 1         | Web         | online order      | 1

一連のデータがあまり頻繁に変更されないが、それでも随時列挙する必要がある場合に、これらのテーブルを使用するのが好きです。

お役に立てれば!

75
David Fox

実は、Davidは彼の解決策にぴったりだと言わざるを得ませんが、私を邪魔するトピックがいくつかあります。

  1. モデルをビューに送信しないでください=>これは正しいです
  2. ViewModelを作成し、ViewModelにメンバーとしてモデルを含めると、モデルをビューに効果的に送信しました=>これはBAD
  3. 辞書を使用してオプションをビューに送信します=>このスタイルが良くありません

それでは、どうすればより良い結合を作成できますか?

AutoMapperまたは ValueInjecter のようなツールを使用して、ViewModelとModelの間をマッピングします。 AutoMapperはより良い構文と感触を持っているようですが、現在のバージョンには非常に厳しいトピックがありません:ViewModelからModelへのマッピングを実行できません(平坦化などがありますが、これはトピックから外れています)したがって、現時点ではValueInjecterを使用することを好みます。

そのため、ビューに必要なフィールドを使用してViewModelを作成します。ルックアップとして必要なSelectListアイテムを追加します。そして、すでにそれらをSelectListsとして追加しています。したがって、LINQ対応のソースからクエリを実行し、IDとテキストフィールドを選択して選択リストとして保存できます。ルックアップとして新しいタイプ(辞書)を作成する必要はなく、_new SelectList_を移動するだけです。ビューからコントローラーへ。

_  // StaffTypes is an IEnumerable<StaffType> from dbContext
  // viewModel is the viewModel initialized to copy content of Model Employee  
  // viewModel.StaffTypes is of type SelectList

  viewModel.StaffTypes =
    new SelectList(
        StaffTypes.OrderBy( item => item.Name )
        "StaffTypeID",
        "Type",
        viewModel.StaffTypeID
    );
_

ビューで呼び出す必要があるのは

_@Html.DropDownListFor( model => mode.StaffTypeID, model.StaffTypes )
_

コントローラーのメソッドのpost要素に戻り、ViewModel型のパラメーターを取得する必要があります。次に、検証を確認します。検証が失敗した場合、_viewModel.StaffTypes_ SelectListを再入力することを忘れないでください。この関数はpost関数に入るとnullになるためです。だから私はそれらの人口の事を機能に分離する傾向があります。何か問題がある場合は、return new View(viewModel)をコールバックするだけです。 MVC3によって検出された検証エラーは、ビューに自動的に表示されます。

独自の検証コードがある場合、それらが属するフィールドを指定することで検証エラーを追加できます。 ModelStateのドキュメントを確認して、その情報を入手してください。

viewModelが有効な場合、次の手順を実行する必要があります。

新しいアイテムの作成である場合は、viewModelからモデルを作成する必要があります(ValueInjecterが最適です)。次に、そのタイプのEFコレクションに追加して、変更をコミットできます。

更新がある場合、最初に現在のデータベース項目をモデルに取得します。その後、viewModelからモデルに値をコピーして戻すことができます(ここでもValueInjecterを使用すると、非常にすばやく実行できます)。その後、SaveChangesを実行できます。

不明な点がある場合はお気軽にお問い合わせください。

23
nttakr