NerdDinnerチュートリアル

NerdDinnerステップ3:モデルの構築

Scott Guthrie 著/Chica
2009/06/19

 本記事は、Microsoftの本社副社長であり、ASP.NETやSilverlightなどの開発チームを率いるScott Guthrie氏が公開している「NerdDinner Tutorial」を翻訳したものです。氏の許可を得て転載しています。

[これは無償の"NerdDinner"アプリケーション・チュートリアルのステップ3で、ASP.NET MVCを使用して、小さいながらも完全なWebアプリケーションを構築する手順を紹介しています。]

 モデル−ビュー−コントローラのフレームワークにおいて、“モデル”という言葉は、アプリケーションのデータを表すオブジェクトのことであり、検証およびビジネス・ルールが統合されたドメイン・ロジックを表すオブジェクトのことです。モデルは多くの場合でMVCベースのアプリケーションの“中心”であり、後で説明しているように、基本的にはその動作を操作することになります。

 ASP.NET MVCフレームワークはすべてのデータ・アクセス技術をサポートしており、開発者はリッチな.NETデータのオプションから選択して、それらのモデルを実装できます。これには、LINQ to Entities、LINQ to SQL、NHibernate、LLBLGen Pro、SubSonic、WilsonORM、または単なる生のADO.NET DataReaderもしくはDataSetなどが含まれます。

 NerdDinnerアプリケーションでは、LINQ to SQLを使用して、データベースのデザインにかなり近い形で対応する簡単なモデルを作成し、いくつかの独自の検証ロジックとビジネス・ルールを追加します。その後、アプリケーションの残りの部分からデータ永続化の実装を独立させるのに役立ち、単体テストの実行も簡単にするリポジトリ・クラスを実装します。

LINQ to SQL

 LINQ to SQLは、ORM(オブジェクト・リレーショナル・マッパー)で、.NET 3.5の一部として出荷されています。

 LINQ to SQLは、私たちがコードを書いている.NETクラスに、データベースのテーブルを簡単にマッピングする方法を提供しています。NerdDinnerアプリケーションでは、これを使ってデータベースのDinnersおよびRSVPテーブルを、DinnerおよびRSVPクラスにマッピングします。DinnersおよびRSVPテーブルの列は、DinnerおよびRSVPクラスのプロパティに対応します。各DinnerおよびRSVPオブジェクトは、データベースのDinnersまたはRSVPテーブルにある個々の行を表します。

 LINQ to SQLでは、データベースのデータを含んだDinnerやRSVPオブジェクトを検索または更新するのに、SQL文を手動で組み立てる必要がありません。その代わりに、DinnerやRSVPクラス、それらとデータベースとのマッピング、それらの間のリレーションシップを定義します。そうすると、LINQ to SQLは実行時に適切なSQL実行ロジックを生成するので、私たちはそれを利用できます。

 VBおよびC#でサポートされているLINQ言語を使用して、データベースからDinnerおよびRSVPオブジェクトを取得する式クエリを書くことができます。これにより、書くべきコードの量が最小化され、非常にクリーンなアプリケーションを構築できます。

LINQ to SQLクラスをプロジェクトに追加

 まずプロジェクトにある“Models”フォルダを右クリックして、[追加]−[新しい項目]メニュー・コマンドを選択します。


図1

 これにより“新しい項目の追加”ダイアログがポップアップします。“データ”カテゴリで絞って、その中の“LINQ to SQLクラス”テンプレートを選択します。


図2

 その項目に“NerdDinner”と名前を付けて“追加”ボタンをクリックします。Visual StudioはNerdDinner.dbmlファイルを\Modelsディレクトリの下に追加し、LINQ to SQLオブジェクト・リレーショナル・デザイナを開きます。


図3

LINQ to SQLでデータモデル・クラスを作成

 LINQ to SQLでは、既存のデータベース・スキーマから簡単にデータモデル・クラスを作成できます。これを行うには、サーバ・エクスプローラからNerdDinnerデータベースを開き、そこでモデル化したいテーブルを選択します。


図4

 そして、LINQ to SQLデザイナ上に、それらのテーブルをドラッグします。これにより、LINQ to SQLはテーブルのスキーマを使用して、自動でDinnerおよびRSVPクラスを作成します(クラスのプロパティはデータベースのテーブルの列にマッピングされています)。


図5

 デフォルトでは、LINQ to SQLデザイナはデータベースのスキーマに基づいてクラスを作成する際に、自動的にテーブルや列の名前を“複数形化”します。例えば、上記の例にある“Dinners”テーブルは“Dinner”クラスになります。このクラスの名前付けにより、.NETの名前付け規約と一貫したモデルとすることができ、たいていの場合、私はこのデザイナによる修正が便利だと感じています(特に多くのテーブルを追加するとき)。もし、このデザイナが生成するクラスやプロパティの名前が嫌な場合は、いつでも上書きして好きな名前に変更できます。これを行うには、デザイナの中でエンティティ/プロパティ名を直接編集するか、プロパティ・グリッドで修正します。

 また、デフォルトでLINQ to SQLデザイナは、テーブル間の主キー/外部キーのリレーションシップを調べ、それに応じて自動で異なるモデル・クラス間のデフォルトの“リレーションシップ関連付け”を作成します。例えば、DinnerとRSVPテーブルをLINQ to SQLデザイナにドラッグした場合、RSVPテーブルがDinnerテーブルに対して外部キーを持っているという事実に基づき、その2つの間に1対多のリレーションシップ関係があると推測します(これはデザイナで矢印によって示されます)。


図6

 上記の関係により、LINQ to SQLは、開発者がRSVPに関連付いているDinnerにアクセスするために使用できる、強く型付けされた“Dinner”プロパティをRSVPクラスに追加します。また、Dinnerクラスに“RSVPs”コレクション・プロパティを追加するため、開発者は特定のDinnerに関連付いているRSVPオブジェクトの検索および更新ができるようになります。

 以下は、新しいRSVPオブジェクトを作成し、DinnerのRSVPsコレクションへそれを追加する際のVisual StudioでのIntelliSenseの例です。LINQ to SQLが自動的にDinnerオブジェクト上に“RSVPs”コレクションを追加しているのを確認してください。


図7

 RSVPオブジェクトをDinnerのRSVPsコレクションに追加することで、データベースのDinnerとRSVPの行の間に、外部キーによるリレーションシップの関連付けをLINQ to SQLに指示しています。


図8

 もしデザイナによるテーブル関係のモデル化や名前付け方法が嫌な場合、それはオーバーライドできます。デザイナで関連矢印をクリックし、プロパティ・グリッドからそのプロパティにアクセスして、名前の変更、削除、修正をするだけです。NerdDinnerアプリケーションでは、構築中のデータモデル・クラスに対して、このデフォルトの関連付けルールがうまく働いており、そのままこのデフォルトの動作を使用しています。

NerdDinnerDataContextクラス

 Visual Studioは、LINQ to SQLデザイナを使用して定義されたモデルとデータベース・リレーションシップを表す.NETクラスを自動的に作成します。また、ソリューションに追加された各LINQ to SQLデザイナのファイルに対して、LINQ to SQL DataContextクラスも生成します。LINQ to SQLクラス項目を“NerdDinner”と名前付けたため、その作成されるDataContextクラスは“NerdDinnerDataContext”という名前になります。このNerdDinnerDataContextクラスは、私たちがデータベースを操作するための主要な手段になります。

 NerdDinnerDataContextは2つのプロパティ、“Dinners”と“RSVPs”を公開しており、これはデータベースでモデル化した2つのテーブルを表しています。データベースからDinnerまたはRSVPオブジェクトを検索したり取得したりするために、これらのプロパティに対してC#でLINQクエリを書くことができます。

 以下のコードは、NerdDinnerDataContextオブジェクトのインスタンス化と、今後発生する一連のDinnersデータを取得するためのLINQクエリを実行する方法を示しています。Visual StudioはLINQクエリを書く際に、完全なIntelliSense機能を提供し、そこから返されたオブジェクトは強く型付けされていて、IntelliSenseもサポートします。


図9

 DinnerおよびRSVPオブジェクトへのクエリが可能になるのに加えて、取得したDinnerおよびRSVPオブジェクに対して行った、すべての変更の追跡もNerdDinnerDataContextが自動的に行います。この機能を使えば、明示的にSQLの更新コードを書かなくても、簡単にデータベースへ変更を保存できます。

NerdDinnerDataContext db = new NerdDinnerDataContext();

// DinnerID=1の行のDinnerオブジェクトを取得
Dinner dinner = db.Dinners.Single(d => d.DinnerID == 1);

// Dinnerの2つのプロパティを更新
dinner.Title = "タイトルの変更";
dinner.Description = "この夕食会は楽しくなりそうです。";

// データベースへ永続的変更
db.SubmitChanges();

 上記コードのNerdDinnerDataContextオブジェクトは、そこから取得したDinnerオブジェクトへのプロパティの変更を自動的に追跡しています。“SubmitChanges()”メソッドを呼び出したとき、適切なSQLの“UPDATE”文をデータベースに対して実行し、更新された値を保持します。

DinnerRepository クラスの作成

 小さいアプリケーションでは、LINQ to SQLのDataContextクラスに対して直接コントローラから操作を行うようにし、コントローラにLINQクエリを埋め込んでも問題のないケースもあります。しかしアプリケーションが大きくなるにつれ、この方法は保守やテストが大変になります。また、複数の場所で同じLINQクエリを重複させることにもつながります。

 アプリケーションの保守やテストを簡単にする1つの方法は、“リポジトリ”パターンを使用することです。リポジトリ・クラスは、データのクエリや永続化ロジックのカプセル化に貢献し、データの永続化実装の詳細をアプリケーションから取り去ります。アプリケーションのコードをクリーンにするほか、リポジト・リパターンを使用すると、今後のデータ保存の実装が簡単に変更できるようになり、実際のデータベースがなくても、アプリケーションの単体テストができるようになります。

 NerdDinnerアプリケーションには、以下のシグネチャを持つDinnerRepositoryクラスを定義します。

public class DinnerRepository {

  // クエリ・メソッド
  public IQueryable<Dinner> FindAllDinners();
  public IQueryable<Dinner> FindUpcomingDinners();
  public Dinner             GetDinner(int id);

  // 挿入/削除
  public void Add(Dinner dinner);
  public void Delete(Dinner dinner);

  // 保存
  public void Save();
}

注: 本章の後で、このクラスからIDinnerRepositoryインターフェイスを抽出し、コントローラ上でそれを使用して依存性の注入(dependency injection)ができるようにします。まずは単純なところから始めために、DinnerRepositoryクラスを直接操作します。

 このクラスを実装するには、“Models”フォルダを右クリックして、[追加]−[新しい項目]メニュー・コマンドを選択します。“新しい項目の追加”ダイアログで、“クラス”テンプレートを選択して、“DinnerRepository.cs”という名前にします。


図10

 そして、DinnerRespositoryクラスを以下のコードを使用して実装します。

public class DinnerRepository {

  private NerdDinnerDataContext db = new NerdDinnerDataContext();

  //
  // クエリ・メソッド

  public IQueryable<Dinner> FindAllDinners() {
    return db.Dinners;
  }

  public IQueryable<Dinner> FindUpcomingDinners() {
    return from dinner in db.Dinners
           where dinner.EventDate > DateTime.Now
           orderby dinner.EventDate
           select dinner;
  }

  public Dinner GetDinner(int id) {
    return db.Dinners.SingleOrDefault(d => d.DinnerID == id);
  }

  //
  // 挿入/削除メソッド

  public void Add(Dinner dinner) {
    db.Dinners.InsertOnSubmit(dinner);
  }

  public void Delete(Dinner dinner) {
    db.RSVPs.DeleteAllOnSubmit(dinner.RSVPs);
    db.Dinners.DeleteOnSubmit(dinner);
  }

  //
  // 保存

  public void Save() {
    db.SubmitChanges();
  }
}

DinnerRepositoryクラスを使用した検索、更新、挿入、削除

 DinnerRepositoryクラスが作成できたので、それを使用してできる一般的なタスクのいくつかのコード例を見てみましょう。

■検索時の例

 以下のコードはDinnerIDの値を使用して、1つのDinnerを取得します。

DinnerRepository dinnerRepository = new DinnerRepository();

// DinnerIDで特定の夕食会を取得
Dinner dinner = dinnerRepository.GetDinner(5);

 以下のコードはすべての未開催の夕食会を取得し、それをループしています。

DinnerRepository dinnerRepository = new DinnerRepository();

// すべての未開催の夕食会を取得
var upcomingDinners = dinnerRepository.FindUpcomingDinners();

// すべての未開催の夕食会をループしてタイトルを出力
foreach (Dinner dinner in upcomingDinners) {
  Response.Write("タイトル" + dinner.Title);
}

■挿入と更新の例

 以下のコードは、2つの新しい夕食会を追加する例です。リポジトリへの追加/修正は“Save()”メソッドが呼び出されるまでデータベースにコミットされません。LINQ to SQLは自動的にすべての変更を、データベースの1つのトランザクションにラップします。そのためリポジトリの保存時には、すべてが変更されるか何も起らないかのどちらかになります。

DinnerRepository dinnerRepository = new DinnerRepository();

// 最初のDinnerを作成
Dinner newDinner1 = new Dinner();
newDinner1.Title = "Scottとの夕食会";
newDinner1.HostedBy = "ScotGu";
newDinner1.ContactPhone = "425-703-8072";

// 2つ目のDinnerを作成
Dinner newDinner2 = new Dinner();
newDinner2.Title = "Billとの夕食会";
newDinner2.HostedBy = "BillG";
newDinner2.ContactPhone = "425-555-5151";

// Dinnerをリポジトリへ追加
dinnerRepository.Add(newDinner1);
dinnerRepository.Add(newDinner2);

// 保存
dinnerRepository.Save();

 以下のコードは、既存のDinnerオブジェクトを取得し、そこにある2つのプロパティを修正します。“Save()”メソッドがリポジトリで呼び出されたとき、その変更はデータベースへコミットされます。

DinnerRepository dinnerRepository = new DinnerRepository();

// DinnerIDで特定の夕食会を取得
Dinner dinner = dinnerRepository.GetDinner(5);

// Dinnerプロパティの更新
dinner.Title = "タイトルを更新";
dinner.HostedBy = "新しいオーナー";

// 保存
dinnerRepository.Save();

 以下のコードは、ある夕食会を取得し、それにRSVPを追加します。これはLINQ to SQLが作成したDinnerオブジェクト上のRSVPsコレクションを使用して行われます(これはデータベースの中で、その2つの間に主キー/外部キーのリレーションシップがあるからです)。“Save()”メソッドがリポジトリ上で呼び出されたとき、その変更はRSVPテーブルの新しい行としてデータベースへ保存されます。

DinnerRepository dinnerRepository = new DinnerRepository();

// DinnerIDで特定の夕食会を取得
Dinner dinner = dinnerRepository.GetDinner(5);

// 新規のRSVPオブジェクトを作成
RSVP myRSVP = new RSVP();
myRSVP.AttendeeName = "ScottGu";

// DinnerのRSVPコレクションへRSVPを追加
dinner.RSVPs.Add(myRSVP);

// 保存
dinnerRepository.Save();

■削除の例

 以下のコードは、既存のDinnerオブジェクトを取得し、それに削除されたというマークを付けます。“Save()”メソッドがリポジトリ上で呼び出されたときに、その削除はデータベースへコミットされます。

DinnerRepository dinnerRepository = new DinnerRepository();

// DinnerIDで特定の夕食会を取得
Dinner dinner = dinnerRepository.GetDinner(5);

// Dinnerオブジェクトに削除マーク
dinnerRepository.Delete(dinner);

// 保存
dinnerRepository.Save();

モデル・クラスに検証とビジネス・ルール・ロジックを統合

 検証とビジネス・ルール・ロジックの統合は、データを扱うアプリケーションでは主要な部分になります。

■スキーマの検証

 モデル・クラスがLINQ to SQLデザイナを使用して定義されたとき、データモデル・クラスにあるプロパティのデータ型は、そのデータベース・テーブルのデータ型に対応します。例えば、もしDinnersテーブルの“EventDate”列が“datetime”の場合、LINQ to SQLが作成したそのデータモデル・クラスは“DateTime”(これはビルドインの.NETデータ型です)に型付けされます。つまり、それに対してコードからint型やbool型を割り当てようとした場合にはコンパイル・エラーになり、実行時に無効なstring型をそれに明示的に変換しようとした場合には、自動的にエラーが発生します。

 LINQ to SQLはまた、文字列を使用している場合に、自動的にSQLの値をエスケープ処理します。これにより、SQLインジェクション攻撃から防御します。

■検証とビジネス・ルール・ロジック

 スキーマの検証は最初のステップとしては便利ですが、まれに不十分なことがあります。多くの現実的なケースでは、複数のプロパティや実行コードまでをカバーし、しばしばモデルの状態(例えば、作成/更新/削除されたものなのか、“アーカイブ化”などのドメイン特有の状況にあるのか)なども認識可能な、よりリッチな検証ロジックを指定できる能力が要求されます。モデル・クラスに対して検証ルールを定義したり、適用したりするのに使用できる、さまざまパターンやフレームワークがあり、またそれに役立つ.NETベースのフレームワークもいくつかあります。ASP.NET MVCアプリケーションでは、ほぼそれらすべてが利用できます。

 NerdDinnerアプリケーションの目的では、Dinnerモデル・オブジェクト上でIsValidプロパティやGetRuleViolations()メソッドを公開するような、比較的簡単で単純なパターンを使用します。IsValidプロパティは、検証やビジネス・ルールがすべて有効かどうかについて真偽を返します。GetRuleViolations()メソッドは、すべてのルール・エラーの一覧を返します。

 今回のDinnerモデルには、プロパティへ“部分クラス”を追加して、IsValidとGetRuleViolations()を実装します。部分クラスは、(LINQ to SQLデザイナが生成したDinnerクラスのように)VSデザイナで保守されるクラスへ、メソッド/プロパティ/イベントを追加するために使用でき、自分のコードがツールによりめちゃくちゃにならないようにします。\Modelsフォルダ上で右クリックして“新しい項目の追加”メニュー・コマンドを選択すると、新しい部分クラスをプロジェクトに追加できます。“新しい項目の追加”ダイアログで“クラス”テンプレートを選択して、Dinner.csという名前にします。


図11

 “追加”ボタンをクリックしてDinner.csファイルをプロジェクトに追加し、IDEでそれを開きます。そうすると、以下のコードを使用して、基本的なルール/検証を実施するフレームワークを実装できます。

public partial class Dinner {

  public bool IsValid {
    get { return (GetRuleViolations().Count() == 0); }
  }

  public IEnumerable<RuleViolation> GetRuleViolations() {
    yield break;
  }

  partial void OnValidate(ChangeAction action) {
    if (!IsValid)
      throw new ApplicationException("ルール違反のため保存しません");
  }
}

public class RuleViolation {

  public string ErrorMessage { get; private set; }
  public string PropertyName { get; private set; }

  public RuleViolation(string errorMessage, string propertyName) {
    ErrorMessage = errorMessage;
    PropertyName = propertyName;
  }
}

上記コードについて、いくつかの注意書き:

  • Dinnerクラスに“partial”キーワードが付与されています。これは、それが含まれるコードはLINQ to SQLデザイナで生成/保守されるクラスと合成され、1つのクラスにコンパイルされることを意味します。
  • RuleViolationクラスは、これからプロジェクトに追加するヘルパー・クラスで、これによりルール違反について、より詳細事項が提供できます。
  • Dinner.GetRuleViolations()メソッドは、検証やビジネス・ルールの評価を行います(もうすぐ実装します)。そして、一連のRuleViolationオブジェクトを返し、すべてのルール・エラーについてのより詳細な情報を提供します。
  • Dinner.IsValidプロパティは便利なヘルパー・プロパティで、DinnerオブジェクトがアクティブなRuleViolationsを持っているかどうかを示します。このため開発者は、Dinnerオブジェクトを使用して、いつでも自由にチェックを行えます(そして例外を発生させません)。
  • Dinner.OnValidate()部分メソッドはLINQ to SQLが提供するフックであり、Dinnerオブジェクトがデータベースに保存されようとするときを知ることができます。上記のOnValidate()実装では、保存する前にDinnerにRuleViolationsがないことを保証します。もし正しくない状態であれば、例外を発生させ、LINQ to SQLにトランザクションを停止させます。

 このアプローチは、検証とビジネス・ルールを統合する単純なフレームワークを提供します。では、GetRuleViolations()メソッドに以下のルールを追加しましょう。

public IEnumerable<RuleViolation> GetRuleViolations() {

  if (String.IsNullOrEmpty(Title))
    yield return new RuleViolation("Title required","Title");

  if (String.IsNullOrEmpty(Description))
    yield return new RuleViolation("Description required","Description");

  if (String.IsNullOrEmpty(HostedBy))
    yield return new RuleViolation("HostedBy required", "HostedBy");

  if (String.IsNullOrEmpty(Address))
    yield return new RuleViolation("Address required", "Address");

  if (String.IsNullOrEmpty(Country))
    yield return new RuleViolation("Country required", "Country");

  if (String.IsNullOrEmpty(ContactPhone))
    yield return new RuleViolation("Phone# required", "ContactPhone");

  if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
    yield return new RuleViolation("Phone# does not match country", "ContactPhone");

  yield break;
}

 C#の“yield return”機能を使用して、一連のRuleViolationsを返します。上記の最初の6つのルール・チェックは、単純にDinner上のstringプロパティがNullまたは空とならないようにします。最後のルールはもう少し面白いもので、ContactPhoneの番号のフォーマットが国のものに合致しているかを検証するために、プロジェクトに追加可能なPhoneValidator.IsValidNumber()ヘルパー・メソッドを呼び出します。

 .NETの正規表現サポートを使用して、この電話番号検証サポートを実装できます。以下はプロジェクトに追加できる簡単なPhoneValidator実装で、これにより、国別のRegexパターン・チェックが追加できます。


public class PhoneValidator {

  static IDictionary<string, Regex> countryRegex = new Dictionary<string, Regex>() {
    { "USA", new Regex("^[2-9]\\d{2}-\\d{3}-\\d{4}$")},
    { "UK", new Regex("(^1300\\d{6}$)|(^1800|1900|1902\\d{6}$)|(^0[2|3|7|8]{1}[0-9]{8}$)|(^13\\d{4}$)|(^04\\d{2,3}\\d{6}$)")},
    { "Netherlands", new Regex("(^\\+[0-9]{2}|^\\+[0-9]{2}\\(0\\)|^\\(\\+[0-9]{2}\\)\\(0\\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\\-\\s]{10}$)")},
  };

  public static bool IsValidNumber(string phoneNumber, string country) {

    if (country != null && countryRegex.ContainsKey(country))
      return countryRegex[country].IsMatch(phoneNumber);
    else
      return false;
  }

  public static IEnumerable<string> Countries {
    get {
      return countryRegex.Keys;
    }
  }
}

■検証とビジネス・ルールの処理

 上記のような検証とビジネス・ルールのコードが追加できたので、Dinnerが作成または更新されたときに、今回の検証ロジック・ルールが評価され、強制されるようになります。

 開発者は以下のようなコードを書いて、いつでもDinnerオブジェクトが有効かどうかを確認し、例外を発生させることなく、その中にあるすべての違反の一覧を取得できます。

Dinner dinner = dinnerRepository.GetDinner(5);

dinner.Country = "USA";
dinner.ContactPhone = "425-555-BOGUS";

if (!dinner.IsValid) {

  var errors = dinner.GetRuleViolations();

  // エラー修正のために何かを行う
}

 正しくない状態でDinnerを保存しようとすると、DinnerRepository上でSave()メソッドを呼び出すときに例外が発生します。これは、LINQ to SQLがDinnerの変更を保存する前に、自動的にDinner.OnValidate()部分クラスを呼び出すようになっており、いまDinner.OnValidate()にコードを追加して、そのDinnerにルール違反が存在する場合は例外を発生するようにしたためです。この例外を捕捉し、違反を修正するために、その一覧を取得できます。

Dinner dinner = dinnerRepository.GetDinner(5);

try {

  dinner.Country = "USA";
  dinner.ContactPhone = "425-555-BOGUS";

  dinnerRepository.Save();
}
catch {

  var errors = dinner.GetRuleViolations();

  // エラー修正のために何かを行う
}

 検証とビジネス・ルールは、UI層内ではなくモデル層内に実装されるため、アプリケーションのすべてのシナリオにわたり適用して使えます。後でビジネス・ルールを変更または追加でき、Dinnerオブジェクトを操作するすべてのコードで、その恩恵を受けることができます。

 アプリケーション全体やUIロジックに影響を与えることなく、1カ所でビジネス・ルールを変更できるという柔軟性は、うまく書かれたアプリケーションのしるしであり、MVCフレームワークが与えてくれる恩恵です。

次のステップ

 データベースの検索および更新の両方に使用できるモデルができました。

 では、その周辺のHTML UI体験を構築するのに使用するいくつかのコントローラとビューをプロジェクトに追加しましょう。

[注:NerdDinnerアプリケーションの完成版はhttp://nerddinner.codeplex.comからダウンロードできます。] End of Article

 
インデックス・ページヘ  「NerdDinnerチュートリアル」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間