-
Notifications
You must be signed in to change notification settings - Fork 55
Tutorial_SPA_CSharp.ja
2016年7月19日
本チュートリアルでの演習に沿ってサンプルプログラムを開発することで、Open 棟梁を使用したシングルページ アプリケーションの開発の流れ・クラスの作成方法・各種定義ファイルの作成方法・ツールの使用方法・実行結果の確認方法などを習得することを目的としています。
また、本チュートリアルでは、主にシングルページ アプリケーションを開発する上での Open 棟梁の利用方法について紹介しています。このため、シングルページ アプリケーションそのものについては詳細には解説していません。シングルページ アプリケーションについて知りたい方は、別途マイクロソフトのサイトを参考してください。
Open 棟梁およびシングルページ アプリケーション開発を検討している SE・開発者。
本チュートリアルでは、Open 棟梁テンプレート・ベース (Visual Studio 2015 用) に付属のサンプルプログラムを題材とし、Open 棟梁を使用したシングルページ アプリケーションの開発の流れを、順を追って説明します。
本ドキュメントに記載の会社名・商品名は、各社の商標または登録商標です。
本ドキュメントは、クリエイティブ・コモンズ CC BY 2.1 JP ライセンスの下で利用可能です。
Open 棟梁は、.NET 用のアプリケーションフレームワークです。Open 棟梁は、.NET Framework 4.6 以上を対象に、C/S(Windows Forms, WPF)、Web(ASP.NET)、RIA(Silverlight) など、さまざまなアプリケーションで利用できます。また、シングルページ アプリケーション (SPA) は、MVC パターン および MVVM パターンを利用した Web アプリケーションを開発するための、ASP.NET のフレームワークです。
Open 棟梁のクラス構成図を図 1-1 に示します。従来の ASP.NET と比べて、SPA であっても、Open 棟梁既存の B 層、D 層部分の構成は変わりません。したがって、これまでに ASP.NET で Open 棟梁を利用したことのある開発者にとっては、B 層、D 層部分の開発ノウハウを活かすことができます。
![](./images/SPA/ClassDiagram.ja.png)
図 1-1 Open 棟梁のクラス構成図
本チュートリアルでは、図 1-1 のクラス構成図に従い、開発者が実装する画面クラス・業務ロジッククラス・DB アクセスクラスの作成方法を、順を追って説明します。なお、本チュートリアルでは、ビューの作成に Razor 構文を使用します。
本チュートリアルでは、以下の環境を前提としています。
- 開発環境
- IDE
- Visual Studio 2015 (Express Edition も利用できます)
- アプリケーション フレームワーク
- Open 棟梁テンプレート・ベース (Visual Studio 2015 用)
- IDE
- 実行環境
- ランタイム
- .NET Framework 4.6
- Web サーバー
- IIS Express
- DB
- SQL Server Express 2008 R2
- ランタイム
- その他
- OS
- Windows 7
- 開発言語
- C#
- OS
あらかじめ、マイクロソフトのサイトなどを参考に、Visual Studio をインストールしておいてください。
次に、Open 棟梁テンプレート・ベース、データベースをセットアップします。
-
GitHub で [Download ZIP] ボタンを押下して OpenTouryoTemplates.zip を入手し、これを解凍して Open 棟梁テンプレート・ベース (Visual Studio 2015 用) を取得します。
-
root_VS2015 フォルダにある Readme.md の手順に従って、Open 棟梁テンプレート・ベースとサンプルデータベースのセットアップを行います。
本チュートリアルでは、Open 棟梁テンプレート・ベースに付属のサンプルプログラムに、画面・ロジックを追加する形で演習を行っていきます。サンプルプログラムの構成を図 3-1 に、チュートリアルの画面遷移図を図 3-2 に示します。
![](./images/SPA/ConfigurationDiagram.ja.png)
図 3-1 サンプルプログラムの構成
本チュートリアルでは、DB アクセスクラス (DAO: Data Access Object) として、以下に示す 3 種類のクラスを作成します。各クラスの詳細については、Open 棟梁の利用ガイド(ベターユース、FAQ 編)をご覧ください。
DB アクセスクラス | 説明 |
---|---|
自動生成 DAO | Open 棟梁付属の D 層自動生成ツールにより生成する DAO クラス。テーブル・ビューに対する単純な CRUD 処理を行う場合に利用する。 |
共通 DAO | Open 棟梁提供の DAO クラス。複数テーブルを結合した結果を取得する場合など、D 層自動生成ツールで自動生成できない処理を行う場合に利用する。 |
DAO 集約クラス | D 層部分のファサードクラス。1 トランザクションで複数 DAO クラスを利用する場合に、B 層からのリクエストを集約させる場合に利用する。 |
![](./images/SPA/ScreenTransitionDiagram.png)
図 3-2 サンプルプログラムの画面遷移図
Open 棟梁を用いた開発の流れを、順を追って説明します。
-
C:\root\programs\C#\Samples\WebApp_sample\SPA_Sample\SPA_Sample.sln
を開きます。 -
Visual Studio が起動し、Open 棟梁テンプレート・ベース(Visual Studio 2015 用)に付属のサンプルプログラムが開かれていることを確認してください。
Open 棟梁では、画面から送信された入力データを「引数クラス」と呼ばれるオブジェクトに保持して、業務ロジック、データアクセスクラスへと受け渡します。また、データアクセスや業務ロジックの結果は「戻り値クラス」と呼ばれるオブジェクトに保持して、画面へと受け渡します。
SPA では、図 1-1 に示しましたように、画面 (View) から JSON 形式で送信された入力データを Web API が受け取ります。Web API が受け取ったデータを引数クラスに格納して、業務ロジック、データアクセスクラスへと受け渡します。業務ロジックやデータアクセスクラスの結果の戻り値クラスは、Web API に返され、Web API から、また JSON 形式に変換されて画面 (View) へと返されます。
本節では、その引数クラス、戻り値クラスを作成します。
-
Visual Studio のソリューション エクスプローラーで
Codes\Common
フォルダを選択し、ツールバーの「プロジェクト(P)」-「クラスの追加(C)」を選択します。 -
OrderParameterValue.cs
という名前のクラスを追加します。 -
以下のコードを
OrderParameterValue.cs
に追加し、Open 棟梁が提供するクラスをインポートします。using Touryo.Infrastructure.Business.Util; using Touryo.Infrastructure.Business.Common;
-
OrderParameterValue
クラスの宣言部分を以下のように修正し、Open 棟梁の「引数親クラス 2」を継承させます。public class OrderParameterValue : MyParameterValue
-
OrderParameterValue
クラスのコンストラクタを以下のように修正します。public OrderParameterValue(string screenId, string controlId, string methodName, string actionType, MyUserInfo user) : base(screenId, controlId, methodName, actionType, user) { }
-
画面から業務ロジックに渡す値として、
OrderParameterValue
クラスに以下のフィールドを追加します。/// <summary>注文 ID</summary> public string OrderId; /// <summary>注文情報(サマリ)</summary> public System.Data.DataTable Orders; /// <summary>注文情報(明細)</summary> public System.Data.DataTable OrderDetails;
-
4.2.1 項と同じように、
Codes\Common
フォルダに、OrderReturnValue.cs
という名前のクラスを追加します。 -
以下のコードを
OrderReturnValue.cs
に追加し、Open 棟梁が提供するクラスをインポートします。using Touryo.Infrastructure.Business.Common;
-
OrderReturnValue
クラスの宣言部分を以下のように修正し、Open 棟梁の「戻り値親クラス 2」を継承させます。public class OrderReturnValue : MyReturnValue
-
画面に返す値として、
OrderReturnValue
クラスに以下のフィールドを追加します。/// <summary>注文情報(サマリ)</summary> public System.Data.DataTable Orders; /// <summary>注文情報(明細)</summary> public System.Data.DataTable OrderDetails;
テーブル・ビューに対する単純な CRUD 処理を行うデータアクセスクラス、SQL ファイルについては、Open 棟梁付属の D 層自動生成ツールで自動生成が可能です。
-
C:\root\programs\C#\Frameworks\DaoGen_Tool\bin\Debug\DaoGen_Tool.exe
を実行し、D 層自動生成ツールを起動します。 -
以下のように値を設定し、「取得」ボタンをクリックします。
- データプロバイダ: SQL Server Client
- 接続文字列: Data Source=localhost\SQLExpress;Initial Catalog=Northwind;Integrated Security=true;
- プルダウン: 概要情報
-
接続文字列等の情報に誤りがなければ、「DBMSのスキーマ情報の表示(概要情報)ダイアログ」が表示されます。
本ダイアログが表示されたことを確認し、「閉じる」ボタンをクリックして、ダイアログを閉じます。
-
「テーブル一覧の取得」ボタンをクリックします。
テーブル名称に関する注意を促すダイアログが表示されますが、「OK」ボタンをクリックして閉じてください。
-
Northwind データベース内のテーブル/ビューがリストに表示されます。本チュートリアルでは Orders テーブルと Order Details テーブルのみ使用しますので、Orders テーブル、Order Details テーブル以外を選択して、「削除」ボタンをクリックします。
-
リスト内の項目が、Orders テーブルと Order Details テーブルのみになったことを確認し、「ロード」ボタンをクリックします。
-
「D層定義情報を生成」ボタンが活性化されますので、出力エンコーディングとして「utf-8」を選択し、「D層定義情報を生成」ボタンをクリックします。
D 層定義情報ファイルの保存ダイアログが表示されますので、
C:\root\Info.csv
にファイルを保存します。 -
D 層定義情報ファイルが正常に生成できたことを示すダイアログが表示されますので、「OK」ボタンをクリックして閉じます。
-
「STEP2へ遷移」ボタンをクリックします。
-
「ステップ2」画面が表示されますので、以下のように値を設定し、「プログラムを生成する」ボタンをクリックします。
- D 層定義情報ファイル: C:\root\Info.csv
- ソーステンプレートフォルダ: C:\root\files\tools\DGenTemplates
- 出力ファイル: C:\root
- 上記以外はデフォルトのまま
-
Dao、SQL ファイルが正常に生成できたことを示すダイアログが表示されますので、「OK」ボタンをクリックして閉じます。
-
C:\root
フォルダ以下に、Dao ファイル、SQL ファイルが生成されていることを確認します。【注意】Open 棟梁では、SQL ファイルとして、拡張子が
.sql
のファイルと、.xml
のファイルがある。(詳しくは Open 棟梁の説明書をご覧ください) -
自動生成した Dao クラスをサンプルプログラムに含めるため、Visual Studio でサンプルプログラムを開き、
AppCode\sample\Dao
フォルダを選択し、ツールバーの「プロジェクト(P)」-「既存の項目の追加(G)」を選択します。 -
既存項目の追加ダイアログで、
C:\root\DaoOrders.cs
とC:\root\DaoOrder_Details.cs
ファイルを選択し、「追加(A)」ボタンをクリックします。 -
C:\root
フォルダ直下に生成された SQL ファイル・XML ファイルを、C:\root\files\resource\Sql
フォルダに移動します。 -
D 層自動生成ツールを終了します。
D 層自動生成ツールでは、単純な CRUD 処理を行う Dao クラスや SQL ファイルを生成できます。しかし、複数のテーブルを結合 (JOIN) させる SQL など、単純な CRUD 処理ではない SQL は、個別に作成する必要があります。
-
C:\root\files\resource\Sql
フォルダに、SelectOrders.sql
ファイルを作成します。 -
SelectOrders.sql
に、以下の SQL 文を記述します。SELECT Orders.OrderID, Customers.CompanyName, Customers.ContactName, Employees.LastName As EmployeeLastName, Employees.FirstName As EmployeeFirstName, Orders.OrderDate FROM Orders INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID
本チュートリアルでは、以下の 3 つの Dao クラスを使用します。
- DaoOrders
- Orders テーブルへのアクセス用
- DaoOrder_Details
- Order Details テーブルへのアクセス用
- CmnDao (Open 棟梁の共通 Dao)
- 4.5.2 項で作成した SQL ファイルを使用したアクセス用
これらの Dao クラスの呼び出しを制御し、業務ロジッククラス (B 層クラス) に対する窓口 (ファサード) となる、DAO 集約クラスを作成します。
-
Visual Studio のソリューション エクスプローラーで、
Logic\Dao
フォルダを選択し、ツールバーの「プロジェクト(P)」-「クラスの追加(C)」を選択します。 -
ConsolidatedLayerD.cs
という名前のクラスを追加します。 -
以下のコードを
ConsolidatedLayerD.cs
に追加し、Open 棟梁が提供するクラスをインポートします。// Open棟梁 using Touryo.Infrastructure.Business.Dao; using Touryo.Infrastructure.Public.Db; // 引数・戻り値クラス using SPA_Sample.Codes.Common;
-
ConsolidatedLayerD
クラスの宣言部分を以下のように修正し、Open 棟梁の「DAO 集約親クラス」を継承させます。public class ConsolidatedLayerD : BaseConsolidateDao
-
ConsolidatedLayerD
クラスに、以下のようにコンストラクタを作成します。public ConsolidatedLayerD(BaseDam dam) : base(dam) { }
-
ConsolidatedLayerD
クラスに、注文情報一覧を取得するGetOrders
メソッドを作成します。public OrderReturnValue GetOrders(OrderParameterValue orderParameter) { // 戻り値クラスを作成する OrderReturnValue returnValue = new OrderReturnValue(); // 共通 DAO を作成する (SQL ファイルとして、4.5.2 項で作成したファイルを使用する) CmnDao dao = new CmnDao(this.Dam); dao.SQLFileName = "SelectOrders.sql"; // 結果格納用の DataTable System.Data.DataTable table = new System.Data.DataTable(); // DB から注文情報一覧を取得し、DataTable に格納する dao.ExecSelectFill_DT(table); // 戻り値クラスに注文情報一覧を格納し、B 層クラスに返す returnValue.Orders = table; return returnValue; }
-
同様に、注文 ID をもとに、注文情報の詳細を取得する
GetOrderById
メソッドを作成します。public OrderReturnValue GetOrderById(OrderParameterValue orderParameter) { // 戻り値クラスを作成する OrderReturnValue returnValue = new OrderReturnValue(); // 自動生成した D 層クラスのインスタンスを生成する DaoOrders orderDao = new DaoOrders(this.Dam); DaoOrder_Details orderDetailsDao = new DaoOrder_Details(this.Dam); // 注文情報、注文詳細情報を格納するための DataTable System.Data.DataTable orderTable = new System.Data.DataTable(); System.Data.DataTable orderDetailsTable = new System.Data.DataTable(); // パラメータを設定する orderDao.PK_OrderID = orderParameter.OrderId; orderDetailsDao.PK_OrderID = orderParameter.OrderId; // 注文 ID をもとに注文情報を検索する orderDao.D2_Select(orderTable); orderDetailsDao.D2_Select(orderDetailsTable); // 戻り値クラスに結果セットを格納し、B 層クラスに返す returnValue.Orders = orderTable; returnValue.OrderDetails = orderDetailsTable; return returnValue; }
-
同様に、画面で入力した注文情報を DB に反映する
UpdateOrder
メソッドを作成します。public OrderReturnValue UpdateOrder(OrderParameterValue orderParameter) { // 戻り値クラスを作成する OrderReturnValue returnValue = new OrderReturnValue(); // 自動生成した D 層クラスのインスタンスを生成する DaoOrders orderDao = new DaoOrders(this.Dam); DaoOrder_Details orderDetailsDao = new DaoOrder_Details(this.Dam); // 注文情報、注文詳細情報を格納するための DataTable System.Data.DataTable orderTable = orderParameter.Orders; System.Data.DataTable orderDetailsTable = orderParameter.OrderDetails; // レコードの状態を確認し、修正されていたら DB を更新する if (orderTable.Rows[0].RowState == System.Data.DataRowState.Modified) { // 注文情報(サマリ)更新用のパタメータを設定する orderDao.PK_OrderID = orderTable.Rows[0]["OrderId"]; orderDao.Set_OrderDate_forUPD = orderTable.Rows[0]["OrderDate"]; orderDao.Set_RequiredDate_forUPD = orderTable.Rows[0]["RequiredDate"]; orderDao.Set_ShippedDate_forUPD = orderTable.Rows[0]["ShippedDate"]; orderDao.Set_ShipVia_forUPD = orderTable.Rows[0]["ShipVia"]; orderDao.Set_Freight_forUPD = orderTable.Rows[0]["Freight"]; orderDao.Set_ShipName_forUPD = orderTable.Rows[0]["ShipName"]; orderDao.Set_ShipAddress_forUPD = orderTable.Rows[0]["ShipAddress"]; orderDao.Set_ShipCity_forUPD = orderTable.Rows[0]["ShipCity"]; orderDao.Set_ShipRegion_forUPD = orderTable.Rows[0]["ShipRegion"]; orderDao.Set_ShipPostalCode_forUPD = orderTable.Rows[0]["ShipPostalCode"]; orderDao.Set_ShipCountry_forUPD = orderTable.Rows[0]["ShipCountry"]; // 注文情報(サマリ)を更新する orderDao.D3_Update(); } foreach (System.Data.DataRow row in orderDetailsTable.Rows) { // レコードの状態を確認し、修正されていたら DB を更新する if (row.RowState == System.Data.DataRowState.Modified) { // 注文情報(明細)更新用のパラメータを設定する orderDetailsDao.PK_OrderID = row["OrderId"]; orderDetailsDao.PK_ProductID = row["ProductId"]; orderDetailsDao.Set_UnitPrice_forUPD = row["UnitPrice"]; orderDetailsDao.Set_Quantity_forUPD = row["Quantity"]; orderDetailsDao.Set_Discount_forUPD = row["Discount"]; // 注文情報(明細)を更新する orderDetailsDao.D3_Update(); } } // 戻り値クラスをB層クラスに返す(更新処理のため、戻り値はなし) return returnValue; }
-
Visual Studio のソリューション エクスプローラーで、
Logic\Business
フォルダを選択し、ツールバーの「プロジェクト(P)」-「クラスの追加(C)」を選択します。 -
OrdersLogic.cs
という名前のクラスを追加します。 -
以下のコードを
OrdersLogic.cs
に追加し、Open 棟梁が提供するクラス、引数・戻り値クラス、D 層クラスをインポートします。// 業務フレームワーク using Touryo.Infrastructure.Business.Business; using Touryo.Infrastructure.Business.Common; using Touryo.Infrastructure.Business.Dao; using Touryo.Infrastructure.Business.Exceptions; using Touryo.Infrastructure.Business.Presentation; using Touryo.Infrastructure.Business.Util; // フレームワーク using Touryo.Infrastructure.Framework.Business; using Touryo.Infrastructure.Framework.Common; using Touryo.Infrastructure.Framework.Dao; using Touryo.Infrastructure.Framework.Exceptions; using Touryo.Infrastructure.Framework.Presentation; using Touryo.Infrastructure.Framework.Util; using Touryo.Infrastructure.Framework.Transmission; using Touryo.Infrastructure.Framework.RichClient.Presentation; // 部品 using Touryo.Infrastructure.Public.Db; using Touryo.Infrastructure.Public.IO; using Touryo.Infrastructure.Public.Log; using Touryo.Infrastructure.Public.Str; using Touryo.Infrastructure.Public.Util; // 引数・戻り値クラス using SPA_Sample.Codes.Common; // DAO クラス using SPA_Sample.Codes.Dao;
-
OrdersLogic
クラス宣言部分を以下のように修正し、Open 棟梁の「業務親クラス 2」を継承させます。public class OrdersLogic : MyFcBaseLogic
-
OrdersLogic
クラスに、注文情報一覧取得用のUOC_GetOrders
メソッド・注文 ID をもとに注文情報の詳細を取得するためのUOC_GetOrderById
メソッド・注文情報更新用のUOC_UpdateOrder
メソッドを作成します。ただし、DAO クラスの呼び出しは DAO 集約クラスが行いますので、B 層クラスは、P 層クラスと DAO 集約クラスの中継のみを行います。private void UOC_GetOrders(OrderParameterValue orderParameter) { // DAO 集約クラスを生成する ConsolidatedLayerD facade = new ConsolidatedLayerD(this.GetDam()); // 注文情報一覧を取得する OrderReturnValue returnValue = facade.GetOrders(orderParameter); // 戻り値クラスを返す this.ReturnValue = returnValue; } private void UOC_GetOrderById(OrderParameterValue orderParameter) { // DAO 集約クラスを生成する ConsolidatedLayerD facade = new ConsolidatedLayerD(this.GetDam()); // 注文情報の詳細を取得する OrderReturnValue returnValue = facade.GetOrderById(orderParameter); // 戻り値クラスを返す this.ReturnValue = returnValue; } private void UOC_UpdateOrder(OrderParameterValue orderParameter) { // DAO 集約クラスを生成する ConsolidatedLayerD facade = new ConsolidatedLayerD(this.GetDam()); // 注文情報をDBに登録する OrderReturnValue returnValue = facade.UpdateOrder(orderParameter); // 戻り値クラスを返す this.ReturnValue = returnValue; }
【注意】Open 棟梁の「業務親クラス 2」である
MyFcBaseLogic
クラスを継承した B 層クラスでは、P 層から呼び出されるメソッド名はUOC_xx
(xx は任意) とする必要があります。P 層から ”xx” の部分をパラメータとして渡すことで、Open 棟梁によりUOC_xx
メソッドに処理が振り分けられます。(後述)
本節では、画面からのリクエストを受け取る「Controllerクラス」、画面に表示するデータやコマンドなどを定義する「ViewModel」、画面表示を行う「View」を作成します。
なお、本チュートリアルでは、Visual Studio の SPA テンプレートに既定で同梱されている「Knockout」と呼ばれる JavaScript フレームワークを使用します。このため、ViewModel および View の作成部分は、この Knockout フレームワークの記法にしたがう必要があります。もし実際の案件で、Angular / Angular 2 / React など、他の JavaScript フレームワークを使用する場合は、4.5.2 項および 4.5.3 項を、適宜使用するフレームワークの記法に読み替えてください。(図 1-1 に示した全体的なクラス構成は、使用する JavaScript フレームワークの差異に大きく影響しません)
まず、View からのリクエストを受け付ける Web API を作成します。Web API へは JavaScript フレームワークを介して、View の入力データが JSON 形式で送信されます。
-
View と Web API の間で受け渡される JSON フォーマットを定義します。このとき、
{ "名前": "値" }
のように、JSON データの名前と、どのような値 (データ型) が送信されるかを決定します。本チュートリアルでは、以下のように定義します。-
一覧取得機能
-
View -> Web API
{} (受け渡すデータなし)
-
Web API -> View
[{"OrderID": 注文番号, "CustomerID": 顧客番号, "EmployeeID": 従業員番号, "OrderDate": 注文日, "RequiredDate": 所要期日, "ShippedDate": 出荷日, "ShipVia": 輸送方法, "Freight": 輸送料, "ShipName": お届け先氏名, "ShipAddress": お届け先住所, "ShipCity": お届け先都市, "ShipRegion": お届け先地方, "ShipPostalCode": お届け先郵便番号, "ShipCountry": お届け先国名, "ProductID": 商品番号, "UnitPrice": 単価, "Quantity": 数量, "Discount": 割引}, …] (注文情報のリスト)
-
-
1 件取得
-
View -> Web API
{"OrderID": 注文番号}
-
Web API -> View
{"OrderID": 注文番号, "CustomerID": 顧客番号, "EmployeeID": 従業員番号, "OrderDate": 注文日, "RequiredDate": 所要期日, "ShippedDate": 出荷日, "ShipVia": 輸送方法, "Freight": 輸送料, "ShipName": お届け先氏名, "ShipAddress": お届け先住所, "ShipCity": お届け先都市, "ShipRegion": お届け先地方, "ShipPostalCode": お届け先郵便番号, "ShipCountry": お届け先国名, "ProductID": 商品番号, "UnitPrice": 単価, "Quantity": 数量, "Discount": 割引}
-
-
1 件更新
-
View -> Web API
{"OrderID": 注文番号, "CustomerID": 顧客番号, "EmployeeID": 従業員番号, "OrderDate": 注文日, "RequiredDate": 所要期日, "ShippedDate": 出荷日, "ShipVia": 輸送方法, "Freight": 輸送料, "ShipName": お届け先氏名, "ShipAddress": お届け先住所, "ShipCity": お届け先都市, "ShipRegion": お届け先地方, "ShipPostalCode": お届け先郵便番号, "ShipCountry": お届け先国名, "ProductID": 商品番号, "UnitPrice": 単価, "Quantity": 数量, "Discount": 割引}
-
Web API -> View
{更新されたレコード件数}
-
-
-
先ほど定義した JSON データを格納するためのオブジェクトを作成します。ここで、定義した JSON データの名前と、プロパティの名前を合わせておくと、自動的に送信された JSON データがオブジェクトに格納されます。Visual Studio のソリューション エクスプローラーで、
Models
フォルダを選択し、ツールバーの「プロジェクト(P)」-「クラスの追加(C)」を選択します。 -
WebApiOrderParams.cs
という名前のクラスを追加します。 -
WebApiOrderParams.cs
に、JSON フォーマットでデータを送るためのプロパティを追加します。(先述のとおり、プロパティの名前は、JSON データの名前に合わせておきます)/// <summary>Order ID</summary> public string OrderId { get; set; } /// <summary>Product ID</summary> public string ProductId { get; set; } /// <summary>Unit Price</summary> public string UnitPrice { get; set; } /// <summary>Quantity</summary> public string Quantity { get; set; } /// <summary>Discount</summary> public string Discount { get; set; } /// <summary>Customer ID</summary> public string CustomerID { get; set; } /// <summary>Employee ID</summary> public string EmployeeID { get; set; } /// <summary>Order Date</summary> public string OrderDate { get; set; } /// <summary>Required Date</summary> public string RequiredDate { get; set; } /// <summary>Shipped Date</summary> public string ShippedDate { get; set; } /// <summary>Ship Via</summary> public string ShipVia { get; set; } /// <summary>Freight</summary> public string Freight { get; set; } /// <summary>Ship Name</summary> public string ShipName { get; set; } /// <summary>Ship Address</summary> public string ShipAddress { get; set; } /// <summary>Ship City</summary> public string ShipCity { get; set; } /// <summary>Ship Region</summary> public string ShipRegion { get; set; } /// <summary>Ship Postal Code</summary> public string ShipPostalCode { get; set; } /// <summary>Ship Country</summary> public string ShipCountry { get; set; }
-
次に、注文情報画面 (View) を表示するためのコントローラークラスを作成します。Visual Studio で、
Controllers
フォルダを右クリックし、「追加」-「コントローラー」を選択します。 -
コントローラーの追加ダイアログで、以下のように設定し、「追加」ボタンをクリックします。
- コントローラー名: OrderController
- テンプレート: 空の MVC コントローラー
-
次に、ViewModel からのリクエストを受け取り、業務ロジッククラスを呼び出す Web API コントローラークラスを作成します。
OrderController.cs
に以下のコードを追加し、Open棟梁が提供している名前空間をインポートします。// Open Touryo framework // Business using Touryo.Infrastructure.Business.Business; using Touryo.Infrastructure.Business.Common; using Touryo.Infrastructure.Business.Dao; using Touryo.Infrastructure.Business.Exceptions; using Touryo.Infrastructure.Business.Presentation; using Touryo.Infrastructure.Business.Util; // Framework using Touryo.Infrastructure.Framework.Business; using Touryo.Infrastructure.Framework.Common; using Touryo.Infrastructure.Framework.Dao; using Touryo.Infrastructure.Framework.Exceptions; using Touryo.Infrastructure.Framework.Presentation; using Touryo.Infrastructure.Framework.Util; using Touryo.Infrastructure.Framework.Transmission; // Public using Touryo.Infrastructure.Public.Db; using Touryo.Infrastructure.Public.IO; using Touryo.Infrastructure.Public.Log; using Touryo.Infrastructure.Public.Str; using Touryo.Infrastructure.Public.Util; // Logic inside application using SPA_Sample.Codes.Business; using SPA_Sample.Codes.Common; using SPA_Sample.Models; // System using System.Net; using System.Net.Http; using System.Web.Http; using System.Data;
-
OrderController.cs
の SPA_Sample.Controllers 名前空間に、注文情報を取得する Web API コントローラークラスを作成します。(ここで、送信された JSON データの格納用に、先ほど作成した WebApiOrderParams クラスを引数に指定します)public class GetOrdersController : ApiController { public HttpResponseMessage Post(WebApiOrderParams param) { // Create an object of Parameter Value class OrderParameterValue orderParameterValue = new OrderParameterValue("OrdersList", string.Empty, "GetOrders", "SQL", new MyUserInfo("user01", "192.168.1.1")); // Create objects of Return Value class and Business logic class OrderReturnValue orderReturnValue; OrdersLogic logic = new OrdersLogic(); // Get the list of orders information and store in the return value object orderReturnValue = (OrderReturnValue)logic.DoBusinessLogic(orderParameterValue); if (orderReturnValue.ErrorFlag == true) { // If the Return Value object has error, display the possible error message string message = string.Empty; message = "ErrorMessageID:" + orderReturnValue.ErrorMessageID + ";"; message += "ErrorMessage:" + orderReturnValue.ErrorMessage + ";"; message += "ErrorInfo:" + orderReturnValue.ErrorInfo; Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("Error", message); return Request.CreateResponse(HttpStatusCode.OK, dic); } else { // Display the list of orders information DataTable dt = orderReturnValue.Orders; List<Dictionary<string, string>> list = new List<Dictionary<string, string>>(); foreach (DataRow row in dt.Rows) { Dictionary<string, string> dic = new Dictionary<string, string>(); for (int index = 0; index < dt.Columns.Count; index++) { dic.Add(dt.Columns[index].ColumnName, row[index].ToString()); } list.Add(dic); } return Request.CreateResponse(HttpStatusCode.OK, list); } } }
【注意】上記のように、Web API コントローラーの作成にあたり、以下のルールがある。
- クラス名は必ず「xxxController」とする必要がある。(この "xxx" がコントローラー名となる)
- ApiController クラスを継承する必要がある。
-
次に、注文 ID をもとに注文情報と注文詳細情報を取得するための Web API コントローラークラスを作成します。
public class GetOrderByIdController : ApiController { public HttpResponseMessage Post(WebApiOrderParams param) { // Create an object of Parameter Value class OrderParameterValue orderParameterValue = new OrderParameterValue("OrderInformation", string.Empty, "GetOrderById", "SQL", new MyUserInfo("user01", "192.168.1.1")); // Send Order ID as search condition orderParameterValue.OrderId = param.OrderId; // Create objects of Return Value class and Business logic class OrderReturnValue orderReturnValue; OrdersLogic logic = new OrdersLogic(); // Get the order summary and order details information and store in the return value object orderReturnValue = (OrderReturnValue)logic.DoBusinessLogic(orderParameterValue); if (orderReturnValue.ErrorFlag == true) { // If the Return Value object has error, display the possible error message string message = string.Empty; message = "ErrorMessageID:" + orderReturnValue.ErrorMessageID + ";"; message += "ErrorMessage:" + orderReturnValue.ErrorMessage + ";"; message += "ErrorInfo:" + orderReturnValue.ErrorInfo; Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("Error", message); return Request.CreateResponse(HttpStatusCode.OK, dic); } else { // Display the order information (summary) and order information (details) DataTable dtOrders = orderReturnValue.Orders; List<Dictionary<string, string>>[] list = new List<Dictionary<string, string>>[2]; list[0] = new List<Dictionary<string, string>>(); list[1] = new List<Dictionary<string, string>>(); foreach (DataRow row in dtOrders.Rows) { Dictionary<string, string> dic = new Dictionary<string, string>(); for (int index = 0; index < dtOrders.Columns.Count; index++) { dic.Add(dtOrders.Columns[index].ColumnName, row[index].ToString()); } list[0].Add(dic); } DataTable dtOrderDetails = orderReturnValue.OrderDetails; foreach (DataRow row in dtOrderDetails.Rows) { Dictionary<string, string> dic = new Dictionary<string, string>(); for (int index = 0; index < dtOrderDetails.Columns.Count; index++) { dic.Add(dtOrderDetails.Columns[index].ColumnName, row[index].ToString()); } list[1].Add(dic); } return Request.CreateResponse(HttpStatusCode.OK, list); } } }
-
同様に、注文情報と注文詳細情報を更新するための Web API コントローラークラスを作成する。
public class UpdateOrderController : ApiController { public HttpResponseMessage Post(WebApiOrderParams param) { // Create an object of Parameter Value class OrderParameterValue orderParameterValue = new OrderParameterValue("OrderInformation", string.Empty, "UpdateOrder", "SQL", new MyUserInfo("user01", "192.168.1.1")); // Set the parameters of order summary information orderParameterValue.OrderId = param.OrderId; orderParameterValue.CustomerID = param.CustomerID; orderParameterValue.EmployeeID = param.EmployeeID; orderParameterValue.OrderDate = param.OrderDate; orderParameterValue.RequiredDate = param.RequiredDate; orderParameterValue.ShippedDate = param.ShippedDate; orderParameterValue.ShipName = param.ShipName; orderParameterValue.ShipVia = param.ShipVia; orderParameterValue.ShipAddress = param.ShipAddress; orderParameterValue.ShipCountry = param.ShipCountry; orderParameterValue.ShipCity = param.ShipCity; orderParameterValue.ShipRegion = param.ShipRegion; orderParameterValue.ShipPostalCode = param.ShipPostalCode; orderParameterValue.Freight = param.Freight; // Set the parameters of order details information orderParameterValue.ProductId = param.ProductId; orderParameterValue.UnitPrice = param.UnitPrice; orderParameterValue.Quantity = param.Quantity; orderParameterValue.Discount = param.Discount; // Create objects of Return Value class and Business logic class OrderReturnValue orderReturnValue; OrdersLogic logic = new OrdersLogic(); // Update the order information (summary) and order information (details) orderReturnValue = (OrderReturnValue)logic.DoBusinessLogic(orderParameterValue); // Create an object of string to display message string message = string.Empty; Dictionary<string, string> dic = new Dictionary<string, string>(); if (orderReturnValue.ErrorFlag == true) { // If the Return Value object has error, display the possible error message message = "ErrorMessageID:" + orderReturnValue.ErrorMessageID + ";"; message += "ErrorMessage:" + orderReturnValue.ErrorMessage + ";"; message += "ErrorInfo:" + orderReturnValue.ErrorInfo; dic.Add("Error", message); return Request.CreateResponse(HttpStatusCode.OK, dic); } else { // Display the success message message = "Successfully updated order summary and order details information."; dic.Add("Message", message); return Request.CreateResponse(HttpStatusCode.OK, dic); } } }
-
Visual Studio のソリューション エクスプローラーで、
Scripts\app
フォルダを選択し、ツールバーの「プロジェクト(P)」-「新しい項目の追加(W)」を選択します。 -
Order.viewmodel.js
という名前の JavaScript ファイルを追加します。 -
Order.viewmodel.js
に、OrderViewModel メソッドを作成し、ビューにバインドさせるプロパティおよびコマンドを定義します。function OrderViewModel() { // Orders list, order summary and order details information (JSON format) this.dataOrders = ko.observableArray(); this.dataOrder = ko.observableArray(); this.dataOrderDetails = ko.observableArray(); // Success message this.Result = ko.observable(""); // Error message this.ErrorMessage = ko.observable(""); // Handles visibility Orders list, order summary and order details information this.CanDisplayOrders = ko.observable(true); this.CanDisplayOrderInfo = ko.observable(false); this.CanEditOrderInfo = ko.observable(false); this.DisplayOrders = function () { var self = this; self.CanDisplayOrders(true); self.CanDisplayOrderInfo(false); self.CanEditOrderInfo(false); }; this.DisplayOrderInfo = function () { var self = this; self.CanDisplayOrders(false); self.CanDisplayOrderInfo(true); self.CanEditOrderInfo(false); }; this.EditOrderInfo = function () { var self = this; self.CanDisplayOrders(false); self.CanDisplayOrderInfo(false); self.CanEditOrderInfo(true); }; // Gets the list of Orders this.GetOrders = function () { var self = this; // Reset the error message this.ErrorMessage(""); // Set the parameters in JSON format var param = {} // Ajax request $.ajax({ type: 'POST', url: '/api/GetOrders', data: param, dataType: 'json', success: function (data, dataType) { if (data.error) { // Set the error message self.ErrorMessage(data.error); } else { // Reset the Orders information self.ClearList(); // Enable visibility of Orders self.DisplayOrders(); // Set the list of Orders self.dataOrders(data); } }, error: function (XMLHttpRequest, textStatus, errorThrown) { // Set the error message self.ErrorMessage(XMLHttpRequest.responseText); } }); }; // Get the order summary and order details information this.GetOrderById = function (orderID) { var self = this; // Reset the error message this.ErrorMessage(""); // Set the parameters in JSON format var param = { OrderId: orderID } // Ajax request $.ajax({ type: 'POST', url: '/api/GetOrderById', data: param, dataType: 'json', success: function (data, dataType) { if (data.error) { // Set the error message self.ErrorMessage(data.error); } else { // Reset the orders information self.ClearList(); // Enable visibility of order information self.DisplayOrderInfo(); // Set the order information self.dataOrder(data[0]); self.dataOrderDetails(data[1]); } }, error: function (XMLHttpRequest, textStatus, errorThrown) { // Set the error message self.ErrorMessage(XMLHttpRequest.responseText); } }); }; // Enable the order summary and order details information to edit this.EditOrder = function (data) { var self = this; this.Result(""); self.EditOrderInfo(); self.dataOrderDetails(data); }; // Updates the selected order summary and order details information this.UpdateOrder = function () { var self = this; // Reset the error message this.ErrorMessage(""); // Set the parameters in JSON format var param = { OrderID: self.dataOrder()[0].orderID, CustomerID: self.dataOrder()[0].customerID, EmployeeID: self.dataOrder()[0].employeeID, OrderDate: self.dataOrder()[0].orderDate, RequiredDate: self.dataOrder()[0].requiredDate, ShippedDate: self.dataOrder()[0].shippedDate, ShipVia: self.dataOrder()[0].shipVia, Freight: self.dataOrder()[0].freight, ShipName: self.dataOrder()[0].shipName, ShipAddress: self.dataOrder()[0].shipAddress, ShipCity: self.dataOrder()[0].shipCity, ShipRegion: self.dataOrder()[0].shipRegion, ShipPostalCode: self.dataOrder()[0].shipPostalCode, ShipCountry: self.dataOrder()[0].shipCountry, ProductID: self.dataOrderDetails().productID, UnitPrice: self.dataOrderDetails().unitPrice, Quantity: self.dataOrderDetails().quantity, Discount: self.dataOrderDetails().discount } // Ajax request $.ajax({ type: 'POST', url: '/api/UpdateOrder', data: param, dataType: 'json', success: function (data, dataType) { if (data.error) { // Set the error message self.ErrorMessage(data.error); } else { // Set the success message self.Result(data.message); } }, error: function (XMLHttpRequest, textStatus, errorThrown) { // Set the error message self.ErrorMessage(XMLHttpRequest.responseText); } }); }; // Resets the orders list, order summary and order details information this.ClearList = function () { this.dataOrders([]); this.dataOrder([]); this.dataOrderDetails([]); }; } // Creates Order ViewModel var model = new OrderViewModel(); // Creates dialog to display error message model.ErrorMessage.subscribe(function (newValue) { if (newValue != '') { $('<div>' + newValue + '</div>').dialog({ title: 'Error!', modal: true, resizable: false, height: 600, width: 800, buttons: { 'OK': function (event) { $(this).dialog('close'); } } }); } }); // Activates knockout.js ko.applyBindings(model);
-
Visual Studio で
App_Start\BundleConfig.cs
を開き、Order.viewmodel.js
への参照を定義します。bundles.Add(new ScriptBundle("~/bundles/Order").Include("~/Scripts/app/Order.viewmodel.js"));
-
OrderController
クラスの Index メソッド (のどこか) で右クリックし、「ビューの追加」を選択します。 -
ビューの追加ダイアログで以下のように設定し、「追加」ボタンをクリックします。
- ビュー名: Index
- ビューエンジン: Razor (CSHTML)
- 厳密に型指定されたビューを作成する: チェックなし
- 部分ビューとして作成する: チェックなし
- レイアウトまたはマスターページを使用する: チェックあり
-
注文情報の一覧、および注文情報と注文詳細情報を表示し、注文情報と注文詳細情報を更新するようにビューを定義します。(ここでは、ViewModel に定義した、画面表示可・不可を判定用の CanDisplayOrders メソッド、CanDisplayOrderInfo メソッド、CanEditOrderInfo メソッドの結果をもとに、画面表示を切り替えています)
<!--Title and header information--> @{ ViewBag.Title = "Open Touryo SPA Sample"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div style="width:100%;padding:0.5em 0em;background:#f0f0f0;"> <b style="margin-left:0.4em;font-size:1.5em;">Open Touryo SPA Sample</b> </div> <!--Displays List of Orders--> <div style="width:100%;height:460px;margin-top:0.5em;overflow:scroll;display:none;" data-bind="visible: GetOrders(), style: { display: $root.CanDisplayOrders() === true ? 'block' : 'none' }"> <b style="margin-left:1em;">List of Orders:</b> <table style="width:100%;margin-top:0.5em;font-size:medium;"> <thead> <tr> <th style="width:8%;">Order ID</th> <th style="width:18%">Company Name</th> <th style="width:18%">Contact Name</th> <th style="width:18%">Employee Last Name</th> <th style="width:18%">Employee First Name</th> <th style="width:15%">Order Date</th> </tr> </thead> <tbody data-bind="foreach: dataOrders"> <tr> <td> <a data-bind="text: orderID, click: function(){ $root.GetOrderById($data.orderID) }" href="javascript:void(0)" /> </td> <td data-bind="text: companyName"></td> <td data-bind="text: contactName"></td> <td data-bind="text: employeeLastName"></td> <td data-bind="text: employeeFirstName"></td> <td data-bind="text: orderDate"></td> </tr> </tbody> </table> </div> <!--Displays the order summary and order details information--> <div style="width:100%;display:none;" data-bind="style: { display: CanDisplayOrderInfo() === true ? 'block' : 'none' }"> <!--Displays the Order information (Summary)--> <div style="width: 100%;margin-top:0.5em;"> <b style="margin-left:1em;">Order information (Summary):</b> <table style="width:100%;margin-top:0.5em;font-size:small;"> <thead> <tr> <th>Order ID</th> <th>Customer ID</th> <th>Employee ID</th> <th>Order Date</th> <th>Required Date</th> <th>Shipped Date</th> <th>Ship Via</th> <th>Freight</th> <th>Ship Name</th> <th>Ship Address</th> <th>ShipCity</th> <th>Ship Region</th> <th>Ship PostalCode</th> <th>Ship Country</th> </tr> </thead> <tbody data-bind="foreach: dataOrder"> <tr> <td data-bind="text: orderID"></td> <td data-bind="text: customerID"></td> <td data-bind="text: employeeID"></td> <td data-bind="text: orderDate"></td> <td data-bind="text: requiredDate"></td> <td data-bind="text: shippedDate"></td> <td data-bind="text: shipVia"></td> <td data-bind="text: freight"></td> <td data-bind="text: shipName"></td> <td data-bind="text: shipAddress"></td> <td data-bind="text: shipCity"></td> <td data-bind="text: shipRegion"></td> <td data-bind="text: shipPostalCode"></td> <td data-bind="text: shipCountry"></td> </tr> </tbody> </table> </div> <!--Displays the Order information (Details)--> <div style="width:100%; margin-top:0.5em;"> <b style="margin-left:1em;">Order information (Details):</b> <table style="width:100%;margin-top:0.5em; font-size:small;"> <thead> <tr> <th></th> <th>Order ID</th> <th>Product ID</th> <th>Unit Price</th> <th>Quantity</th> <th>Discount</th> </tr> </thead> <tbody data-bind="foreach: dataOrderDetails"> <tr> <td> <a data-bind="click: function () { $root.EditOrder($data) }" href="javascript:void(0)">Edit</a> </td> <td data-bind="text: orderID"></td> <td data-bind="text: productID"></td> <td data-bind="text: unitPrice"></td> <td data-bind="text: quantity"></td> <td data-bind="text: discount"></td> </tr> </tbody> </table> </div> <!--Action controls--> <div style="width:100%;margin:0.5em 0;"> <div style="float:right;"> <input type="button" id="button1" value="<< Back" data-bind="click: function () { $root.GetOrders() }" /> </div> </div> </div> <!--Displays the order summary and order details information to update--> <div style="width:100%;display:none;" data-bind="style: { display: CanEditOrderInfo() === true ? 'block' : 'none' }"> <!--Update the Order information (Summary)--> <fieldset style="border:1px solid #ddd;width:96%;padding-bottom:1em;"> <legend style="font-weight:bold;display:block;margin-left:3px;"> Update Order information (Summary) </legend> <table style="width:100%;font-size:small;" data-bind="foreach: dataOrder"> <tr> <td style="width:16%;"><b>Order ID</b></td> <td style="width:16%;"> <label style="padding:0.3em 0;background:#f0f0f0;" data-bind="text: orderID" /> </td> <td style="width:16%;"><b>Customer ID</b></td> <td style="width:16%"> <input type="text" data-bind="value: customerID" /> </td> <td style="width:16%;"><b>Employee ID</b></td> <td style="width:16%;"> <input type="text" data-bind="value: employeeID" /> </td> </tr> <tr> <td><b>Order Date</b></td> <td> <input type="text" data-bind="value: orderDate" /> </td> <td><b>Required Date</b></td> <td> <input type="text" data-bind="value: requiredDate" /> </td> <td><b>Shipped Date</b></td> <td> <input type="text" data-bind="value: shippedDate" /> </td> </tr> <tr> <td><b>Ship Via</b></td> <td> <input type="text" data-bind="value: shipVia" /> </td> <td><b>Freight</b></td> <td> <input type="text" data-bind="value: freight" /> </td> <td><b>Ship Name</b></td> <td> <input type="text" data-bind="value: shipName" /> </td> </tr> <tr> <td><b>Ship Address</b></td> <td> <input type="text" data-bind="value: shipAddress" /> </td> <td><b>Ship City</b></td> <td> <input type="text" data-bind="value: shipCity" /> </td> <td><b>Ship Region</b></td> <td> <input type="text" data-bind="value: shipRegion" /> </td> </tr> <tr> <td><b>Ship Postal Code</b></td> <td> <input type="text" data-bind="value: shipPostalCode" /> </td> <td><b>Ship Country</b></td> <td> <input type="text" data-bind="value: shipCountry" /> </td> </tr> </table> </fieldset> <!--Update the Order information (Details)--> <fieldset style="border:1px solid #ddd;width:96%;padding-bottom:1em;"> <legend style="font-weight:bold;display:block;margin-left:3px;"> Update Order information (Details) </legend> <table style="width:100%;font-size:small;" data-bind="foreach: dataOrderDetails"> <tr> <td style="width:16%;"><b>Order ID</b></td> <td style="width:16%;"> <label style="padding:0.3em 0;background:#f0f0f0;" data-bind="text: orderID" /> </td> <td style="width:16%;"><b>Product ID</b></td> <td style="width:16%;"> <label style="padding:0.3em 0;background:#f0f0f0;" data-bind="text: productID" /> </td> <td style="width:16%;"><b>Unit Price</b></td> <td style="width:16%;"> <input type="text" data-bind="value: unitPrice" /> </td> </tr> <tr> <td><b>Quantity</b></td> <td> <input type="text" data-bind="value: quantity" /> </td> <td><b>Discount</b></td> <td> <input type="text" data-bind="value: discount" /> </td> </tr> </table> </fieldset> <!--Action controls--> <div style="width:100%;margin:0.5em 0px;"> <div style="float:left;"> <input type="button" id="button2" value="Update Order Information" data-bind="click: UpdateOrder" /> </div> <div style="float:right;" data-bind="foreach: dataOrder"> <input type="button" id="button3" value="<< Back" data-bind="click: function () {$root.GetOrderById($data.orderID)}" /> </div> </div> <div style="width:100%;margin:0.5em 0;display:inline-block;"> <label id="labelMessage" style="color:#088608;font-weight:bold;" data-bind="text: Result" /> </div> </div> @section scripts{ @Scripts.Render("~/bundles/knockout") @Scripts.Render("~/bundles/jqueryval") @Scripts.Render("~/bundles/Order") }
-
スタートメニューの「プログラムとファイルの検索」ボックスで
services.msc
を実行します。 -
サービス画面から「ASP.NET 状態サービス」を右クリックし、「開始」を選択します。
-
「ASP.NET 状態サービス」の状態が「開始」になったことを確認します。
-
Visual Studio のソリューション エクスプローラーで、
SPA_Sample
プロジェクトを右クリックし、「プロパティ」を選択します。 -
SPA_Sample
プロジェクトのプロパティ画面で、「Web」を選択し、開始動作を以下のように設定します。- 開始動作: ページを指定する
- ページ: Order
-
Visual Studio でサンプルプログラムをデバッグ実行します。
-
注文情報の一覧が表示されることを確認します。
-
Order ID 列のリンクをクリックし、選択した Order ID の注文情報と注文詳細情報が表示されることを確認します。
-
注文詳細情報の「Edit」リンクをクリックします。
【注意】
ここで、「Ship Region」の値が NULL の場合、レコード更新時に Open 棟梁のエラーが発生します。したがって、ここでは、「Ship Region」が NULL でないデータを選択してください。「Ship Region」の値が NULL のデータに対しても更新可能にするには、4.3.1 項で自動生成した SQL ファイルを修正する必要があります。詳細については Open 棟梁の利用ガイド (動的パラメタライズドクエリ編) を参照してください。 -
注文情報と注文詳細情報の編集画面が表示されることを確認します。注文情報と注文詳細情報を編集し、「Update Order Information」ボタンをクリックします。
-
以下のように、成功を示すメッセージが表示され、注文情報と注文詳細情報が更新されたことを確認する。
-
C:\root\files\resource\Log\ACCESS.yyyy-mm-dd.log
をメモ帳などで開きます。(yyyy-mm-dd には、実行日付が入ります) -
業務ロジックの呼び出し履歴が、トレースログとして記録されていることを確認します。
[2016/08/22 00:11:07,450],[INFO ],[9],,user01,192.168.1.1,----->>,OrderDetails,,GetOrders, [2016/08/22 00:11:08,350],[INFO ],[9],,user01,192.168.1.1,<<-----,OrderDetails,,GetOrders,,890,94 [2016/08/22 00:11:18,092],[INFO ],[8],,user01,192.168.1.1,----->>,OrderDetails,,GetOrderById, [2016/08/22 00:11:18,574],[INFO ],[8],,user01,192.168.1.1,<<-----,OrderDetails,,GetOrderById,,481,47 [2016/08/22 00:11:24,337],[INFO ],[7],,user01,192.168.1.1,----->>,OrderDetails,,UpdateOrder, [2016/08/22 00:11:24,700],[INFO ],[7],,user01,192.168.1.1,<<-----,OrderDetails,,UpdateOrder,,362,16
-
C:\root\files\resource\Log\SQLTRACE.yyyy-mm-dd.log
をメモ帳などで開きます。(yyyy-mm-dd には、実行日付が入ります) -
Orders テーブル・Order Details テーブルに対する SQL 文がトレースとして記録されていることを確認します。(以下は SQL トレースログから、SELECT 文の実行ログを抜粋したものです)
[2016/08/22 00:11:08,349],[INFO ],[9],238,31,[commandText]:SELECT Orders.OrderID, Customers.CompanyName, Customers.ContactName, Employees.LastName As EmployeeLastName, Employees.FirstName As EmployeeFirstName, Orders.OrderDate FROM Orders INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID [commandParameter]: [2016/08/22 00:11:18,373],[INFO ],[8],114,16,[commandText]: -- DaoOrders_D2_Select -- 2016/8/3 日立 太郎 SELECT [OrderID], [CustomerID], [EmployeeID], [OrderDate], [RequiredDate], [ShippedDate], [ShipVia], [Freight], [ShipName], [ShipAddress], [ShipCity], [ShipRegion], [ShipPostalCode], [ShipCountry] FROM [Orders] WHERE [OrderID] = @OrderID [commandParameter]:OrderID=10250, [2016/08/22 00:11:18,573],[INFO ],[8],71,0,[commandText]: -- DaoOrder_Details_D2_Select -- 2016/8/3 日立 太郎 SELECT [OrderID], [ProductID], [UnitPrice], [Quantity], [Discount] FROM [Order Details] WHERE [OrderID] = @OrderID [commandParameter]:OrderID=10250, [2016/08/22 00:11:24,530],[INFO ],[7],122,0,[commandText]: -- DaoOrders_D3_Update -- 2016/8/3 日立 太郎 UPDATE [Orders] SET [CustomerID] = @Set_CustomerID_forUPD, [EmployeeID] = @Set_EmployeeID_forUPD, [OrderDate] = @Set_OrderDate_forUPD, [RequiredDate] = @Set_RequiredDate_forUPD, [ShippedDate] = @Set_ShippedDate_forUPD, [ShipVia] = @Set_ShipVia_forUPD, [Freight] = @Set_Freight_forUPD, [ShipName] = @Set_ShipName_forUPD, [ShipAddress] = @Set_ShipAddress_forUPD, [ShipCity] = @Set_ShipCity_forUPD, [ShipRegion] = @Set_ShipRegion_forUPD, [ShipPostalCode] = @Set_ShipPostalCode_forUPD, [ShipCountry] = @Set_ShipCountry_forUPD WHERE [OrderID] = @OrderID [commandParameter]:Set_ShipCity_forUPD=Rio de Janeiro,Set_CustomerID_forUPD=HANAR,OrderID=10250,Set_EmployeeID_forUPD=4,Set_ShippedDate_forUPD=7/12/1996 12:00:00 AM,Set_RequiredDate_forUPD=8/5/1996 12:00:00 AM,Set_ShipName_forUPD=Hanari Carnes,Set_ShipPostalCode_forUPD=05454-876,Set_ShipVia_forUPD=2,Set_ShipAddress_forUPD=Rua do Paco, 67,Set_ShipRegion_forUPD=RJ,Set_OrderDate_forUPD=7/8/1996 12:00:00 AM,Set_ShipCountry_forUPD=Brazil,Set_Freight_forUPD=65.8300, [2016/08/22 00:11:24,699],[INFO ],[7],39,0,[commandText]: -- DaoOrder_Details_D3_Update -- 2016/8/3 日立 太郎 UPDATE [Order Details] SET [UnitPrice] = @Set_UnitPrice_forUPD, [Quantity] = @Set_Quantity_forUPD, [Discount] = @Set_Discount_forUPD WHERE [OrderID] = @OrderID AND [ProductID] = @ProductID [commandParameter]:OrderID=10250,Set_Quantity_forUPD=35,Set_Discount_forUPD=0.15,Set_UnitPrice_forUPD=42.4000,ProductID=51,