WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

スキャフォールディング機能

by WebSurfer 2017年7月23日 18:41

既存のデータベースから Entity Data Model (EDM) を作り、スキャフォールディング機能を使って Create, Read, Update, Delete (CRUD) 操作を行うための ASP.NET MVC アプリを作る手順を備忘録として書いておきます。

完成した Crate 画面

上の画面は作成した ASP.NET MVC アプリの編集 (Create) 画面を IE11 から呼び出して表示したものです。

この記事では、既存のデータベースとして Microsoft のサンプルデータベース Northwind を使用し、その中の Products テーブルの CRUD 操作を行うことにします。

大まかな手順は以下の通りです。

  1. SQL Server にサンプルデータベース Northwind をアタッチして接続できるようにしておく。(LocalDB も使えます。詳しくは先の記事「LocalDB で Northwind と Pubs を利用」を参照)
  2. Visual Studio Community 2015 のテンプレートを使用して ASP.NET MVC5 プロジェクトを生成。
  3. Visual Studio のデザイナを利用して、Northwind データベースから EDM を生成してプロジェクトに追加する。
  4. 追加した EDM をベースに、スキャフォールディング機能を使って CRUD 操作用の Controller と View を自動生成する。

以下に、Visual Studio で上の操作を行った際に表示された画像を貼って要点を書いておきます。自力では一行もコードを書くことなく CRUD 操作が可能な ASP.NET MVC アプリを自動生成できます。

(1) 新しい項目の追加

新しい項目の追加

プロジェクトに EDM を追加するため、ソリューションエクスプローラーでプロジェクトノードを右クリック⇒[追加(D)]⇒[新しい項目(W)...]をクリック。

(2) ADO.NET Entity Data Model を選択

ADO.NET Entity Data Model を選択

表示された「新しい項目の追加」ダイアログで[ADO.NET Entity Data Model]を選択し[追加(A)]をクリック。

(3) モデルのコンテンツの選択

モデルのコンテンツの選択

既存の SQL Server データベースから EDM を生成するため、[データベースから EF Designer]を選択し[次へ(N)]をクリック。

(4) データ接続の選択

データ接続

接続先の SQL Server データベースの指定、接続文字列等の設定を行うため[新しい接続(C)...]をクリック。

(注:上の画像で DefaultConnection というのは Visual Studio のテンプレートでプロジェクトを生成した時に自動的に設定される ASP.NET Identity 用のユーザー情報のストアに使用されるデータベースです)

(5) 接続のプロパティ設定

接続のプロパティ設定

自分の環境では MySQL がデフォルトで選択されているので、これを SQL Server に変更するため[変更(C)...]をクリック。デフォルトで SQL Server が選択されていれば不要な操作です。

(6) データソースの変更

データソースの変更

今回は SQL Server の既定の(または名前付き)インスタンスに接続するため[Microsoft SQL Server]を選択します。

(7) 接続のプロパティ設定

接続のプロパティ設定

[サーバー名(E)]にサーバー名を入力すると[データベース名の選択または入力(D)]にアタッチ済みのデーターベース一覧が表示されるので、その中から Northwind を選択し[OK]ボタンをクリック。

(注:この例では開発マシンにインストールした SQL Server 2008 Express に接続しています。デフォルトでインストールしたので sqlexpress という名前の名前付きインスタンスになっています)

(8) 接続文字列の確認と web.config への保存

接続文字列の確認と web.config への保存

(4) の画面に戻るので、接続文字列とその名前を確認し[次へ(N)]ボタンをクリック。

(9) データベースオブジェクトと設定の選択

データベースオブジェクトと設定の選択

今回の例では Products テーブルの CRUD 操作を行うので[テーブル]にチェックを入れ[完了(F)]ボタンをクリック。

(10) 生成された EDM

生成された EDM

無事 EDM が生成されると上のような画面が表示されます。ソリューションエクスプローラーの .edmx ファイルの下には DbContext を継承したコンテキストクラス、データベースの各テーブルを表すモデルクラスも自動生成されます。

(11) コントローラーの追加

コントローラーの追加

スキャフォールディング機能を利用して Controller と View を MVC アプリに追加します。ソリューションエクスプローラーで Controller フォルダを右クリック⇒[追加(D)]⇒[コントローラー(T)...]をクリック。

(12) スキャフォールディングを追加

スキャフォールディングを追加

上の手順で生成した EDM をベースに Controller と View を一式生成するには[MVC 5 Controller with Views, using Entiry Framework]を選択し[追加」ボタンをクリックします。

(13) コンテキストクラス、モデルクラスの指定

コンテキストクラス、モデルクラスの指定

(10) で生成されたコンテキストクラス、モデルクラスを指定します。今回の例ではコンテキストクラスは NORTHWINDEntities クラス、モデルクラスは Products テーブルの CRUD 操作を行うので Products クラスになります。

[Add]ボタンをクリックすると Controller と View が自動生成されプロジェクトに追加されます。


以上の操作は Visual Studio 2010 で MVC4 アプリを作る場合もほぼ同じですが、生成される EDM, Controller, View はかなり進化しているようです。主な点は以下の通りです。

  1. 生成される EDM は EF6 の DbContext ベース。そのためか、Code First で作ったモデルと DB First で作ったモデルは共存可能になっている。(Visual Studio 2010 ではデフォルトで EF4 の ObjectContext ベース。Code First で作ったモデルとは同じプロジェクト内では共存不可)
  2. 一覧 (Index) 画面には CatrgoryID, SupplierID(数字)ではなく、ナビゲーションプロパティをたどって CategoryName, CompanyName を取得してそれが表示される。さらに、Linq 式に Include メソッドを使いプロパティを先読みするという配慮もされている。
  3. 新規作成 (Create)、編集 (Edit) 画面では CatrgoryID, SupplierID にドロップダウンリストを使用して CategoryName, CompanyName が表示され、ユーザーは数字ではなくそれに該当する名前を見て選択できる。
  4. View には @Html.AntiForgeryToken()、Controller のアクションメソッドには ValidateAntiForgeryToken 属性が自動的に付与される。
  5. オーバーポスティングアタック対策として引数にホワイトリスト(Bind 属性)が自動的に付与される。

Tags: ,

MVC

複数の CheckBox の状態を取得

by WebSurfer 2017年7月2日 17:02

ASP.NET MVC アプリで、複数(数は不定)の CheckBox をレンダリングし、ユーザーがチェックを入れて POST したとき、どのチェックボックスがチェックされているかの状態を取得する方法を備忘録として書いておきます。

CheckBoxList

ユーザーがチェックを入れた CkeckBox からは true を、チェックしてない CheckBox からは false を取得できるようにするのが条件です。

ASP.NET Web Forms アプリですと CheckBoxList というサーバーコントロールがあって、それを使えば複数の CheckBox を実装するのは容易ですが、サーバーコントロールのない ASP.NET MVC アプリでは少々工夫が必要なようです。

html の input type="checkbox" ではチェックされた項目の name=value しか送ってこないのでかえって使いにくいです。Html.EditorFor を使うのがお勧めです。

List<bool> 型のオブジェクトをメンバーとして持つ Model を View に型付け、それから Html.EditorFor を使って CheckBox をレンダリングできます。

その CheckBox は html では input type="checkbox" だけでなく、それとペアで同じ name 属性を持つ隠しフィールド input type="hidden" value="false" も生成されます。

ユーザーがチェックを入れて POST すると、例えば name 属性が Item[0] だった場合、Items[0]=true&Items[0]=false というデータがフォームに含まれて送信されます。(チェックを入れない場合は隠しフィールドの Items[0]=false のみ)

ASP.NET は、モデルバインディングの際、それを見て List<bool> 型のオブジェクトの各要素を true / false に設定しているようです。

以下に、上の画像を表示したサンプルのコードとその説明を書いておきます。

Model と Controller

以下のサンプルではチェックされた項目は ture が、チェックされて無い項目は false がアクションメソッドの引数にバインドされるようにしています。(注:Model と Controller が一緒になっているのは単に分けるのが面倒だったからです)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Mvc4App.Models;

namespace Mvc4App.Controllers
{
  // Model
  public class CheckboxListModel
  {
    public CheckboxListModel()
    {
      Items = new List<bool>();
    }

    public IList<bool> Items { get; set; }
  }
    
  // Controller
  public class ComplexController : Controller
  {        
    [HttpGet]
    public ActionResult Checkboxes()
    {
      // この例では CheckBox を 5 つ作成。初期値は false とし
      // CheckBox はチェックされてない状態とする。
      bool[] defaultItems = 
          new bool[] { false, false, false, false, false };
      CheckboxListModel model = 
          new CheckboxListModel() { Items = defaultItems };
      return View(model);
    }

    [HttpPost]
    // POST されてきたデータは引数の m, items のいずれにもモデル
    // バインドされる。items の方は Model のプロパティ名と一致さ
    // せる必要がある。モデルバインディングの際は大文字・小文字
    // が区別されないので引数名には小文字を使ってプロパティ 
    // Items に以下のように代入できる。
    public ActionResult Checkboxes(CheckboxListModel m, 
                                        IList<bool> items)
    {
      CheckboxListModel model = 
          new CheckboxListModel() { Items = items };
      return View(model);
    }
  }
}

View

EditorFor の引数で m => m.Items[i] としているところがキモです。そうするとレンダリングされる html 要素の name 属性が連番のインデックスを含むようになり、モデルバインディングがうまくいきます。

@model Mvc4App.Controllers.CheckboxListModel

@{
    ViewBag.Title = "Checkboxes";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Checkboxes</h2>

@using (Html.BeginForm()) {
    for (int i = 0; i < Model.Items.Count; i++)
    {
        @Html.EditorFor(m => m.Items[i])
        <br />
    }
    <p>
        <input type="submit" value="Send" />
    </p> 
}

Tags:

MVC

for...in ループと hasOwnProperty

by WebSurfer 2017年6月30日 15:38

JavaScript の for...in ループ内で hasOwnProperty を使っているコード例を見かけますが、hasOwnProperty を使うことにどういう意味があるかを書きます。(詳細は後述しますが、下の画像で赤枠が hasOwnProperty を使わない場合、青枠が使った場合の結果です)

hasOwnProperty 有無の違い

MDN (Mozilla Developer Network) の記事「Object.prototype.hasOwnProperty()」に "in 演算子と違って、このメソッドはオブジェクトのプロトタイプチェーンをたどってチェックしません" と書いてあって、for...in ループの中で hasOwnProperty プロパティを使うコード例もありましたが、自分的にはどうもピンときません。

なので、自分的に納得できる具体例を以下に書いておきます。

マイクロソフト公式解説書「プログラミング Microsoft ASP.NET MVC」の 10.1.2 章に書いてあったことですが、JavaScript でオブジェクト指向を実装するのにプロトタイプを利用できるそうです。だからプロトタイプを使用したコーディングが主流になっているということなのでしょうか?

プロトタイプを使用したコード例として、本に書いてあったように、Person クラスを以下のように定義したとします。

// Person クラスの疑似コンストラクター
var Person = function (name, lastname, birthdate) {
    this.initialize(name, lastname, birthdate);
}

// メンバー
Person.prototype.initialize = 
                 function (name, lastname, birthdate) {
    this.Name = name;
    this.LastName = lastname;
    this.BirthDate = birthdate;
}
        
// メンバー
Person.prototype.getAge = function () {
    return 18;
}

Person クラスの Own プロパティは Name, LastName, BirthDate のみです。しかしながら、以下のコードのように for...in で Person クラスの各要素をコンソールに出力すると、Name, LastName, BirthDate の他に、プロトタイプチェーンをたどって initialize, getAge も出力されてしまいます。上の画像の赤枠で示した部分が下記のコードの実行結果です。

var p = new Person("web", "surfer", "2017/6/30");

for (var key in p) {
    console.log(key + ':' + p[key]);
}

それを、以下のように、p.hasOwnProperty(key) が true になる要素のみをコンソールに出力すれば、上の画像の青枠部分に示した通り、Name, LastName, BirthDate のみとなります。

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + ':' + p[key]);
    }
}

上記は、あくまで自分が思いついた自分的に納得できる例で、他にもっと適切で分かりやすい例があるかもしれませんが・・・

Tags: ,

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年11月  >>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

View posts in large calendar