Skip to content

Tutorial_Automatic_Screen_Generation(DataMaintenance).ja

daisuke nishino edited this page Oct 17, 2018 · 2 revisions

Open 棟梁チュートリアル (結合テーブルに対するデータメンテナンス画面自動生成編)

2017年1月19日

はじめに

本ドキュメントの目的

Open 棟梁の D 層自動生成ツールを使用すると、単一テーブルに対するデータメンテナンス画面を自動生成できます。しかし、D 層自動生成ツールでは結合テーブルに対するデータメンテナンス画面は生成できません。本ドキュメントでは、結合テーブルに対するデータメンテナンス画面の生成方法を紹介します。

本ドキュメントの対象

Open 棟梁を用いた ASP.NET アプリケーション開発で、結合テーブルに対するデータメンテナンス画面の生成を検討している SE および開発者を対象とします。

本ドキュメントの概要

本チュートリアルでは、Visual Studio 2015 向け Open 棟梁テンプレート・ベースに付属のサンプルプログラムを題材とし、結合テーブルに対するデータメンテナンス画面の自動生成手順を、順を追って説明します。

他社所有名称に対する表示

本ドキュメントに記載の会社名・商品名は、各社の商標または登録商標です。

ライセンス

本ドキュメントは、クリエイティブ・コモンズ CC BY 2.1 JP ライセンスの下で利用可能です。

目次

1. Open棟梁の概要

2. 環境設定

3. 本チュートリアルでの演習課題について

4. 演習の準備

5. 演習 1: データメンテナンス画面の生成

6. 演習 2: 自動生成された画面のカスタマイズ

1. Open棟梁の概要

Open 棟梁は、.NET 用のアプリケーションフレームワークです。Open 棟梁は、.NET Framework 4.6 以上を対象に、C/S(Windows Forms, WPF)、Web(ASP.NET)、RIA(Silverlight) など、さまざまなアプリケーションで利用できます。

Open 棟梁のクラス構成図を図 1-1 に示します。

図 1-1 Open 棟梁のクラス構成図

本チュートリアルでは、結合テーブルに対するデータメンテナンス画面を自動生成するための、動的パラメタライズドクエリ・分析ツールの使い方を説明します。本チュートリアルでは、動的パラメタライズドクエリ・分析ツールを「DPQuery_Tool」と略します。DPQuery_Tool は、XML 形式で、テーブル結合の SQL 文を定義できます。また、構文チェックやテスト機能なども持っています。

データメンテナンス画面自動生成機能の概要を、以下に示します。

2. 環境設定

本チュートリアルでは、以下の環境を前提としています。

  • 開発環境
    • IDE
      • Visual Studio 2015 (Express Edition も利用できます)
    • アプリケーション フレームワーク
      • Open 棟梁テンプレート・ベース (Visual Studio 2015 用)
  • 実行環境
    • ランタイム
      • .NET Framework 4.6
    • DB
      • SQL Server Express 2008 R2
  • その他
    • OS
      • Windows 7

あらかじめ、マイクロソフトのサイトなどを参考に、Visual Studio をインストールしておいてください。

次に、Open 棟梁テンプレート・ベース、データベースをセットアップします。

  1. GitHub で [Download ZIP] ボタンを押下して OpenTouryoTemplates.zip を入手し、これを解凍して Open 棟梁テンプレート・ベース (Visual Studio 2015 用) を取得します。

  2. root_VS2015 フォルダにある Readme.md の手順に従って、Open 棟梁テンプレート・ベースとサンプルデータベースのセットアップを行います。

  3. テストテーブル (5 章で使用) 作成用に、任意の場所に createTestTable.sql を作成し、以下のように記述します。(本チュートリアルでは、C:\users\[ユーザー名]\Documents フォルダーに作成します)

    USE [Northwind]
    GO
    /****** Object:    Table [dbo].[TABL1]        Script Date: 05/27/2016 14:12:04 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[TABL1](
        [A] [int] NOT NULL,
        [Y] [varchar](50) NULL,
        [Z] [varchar](50) NULL,
        CONSTRAINT [PK_TABL1] PRIMARY KEY CLUSTERED
        (
            [A] ASC
        ) WITH (PAD_INDEX    = OFF, STATISTICS_NORECOMPUTE    = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS    = ON, ALLOW_PAGE_LOCKS    = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET ANSI_PADDING OFF
    GO
    INSERT [dbo].[TABL1] ([A], [Y], [Z]) VALUES (1, N'Insert_1Y', N'Insert_1Z')
    INSERT [dbo].[TABL1] ([A], [Y], [Z]) VALUES (2, N'Insert_1Y2', N'Insert_1Z2')
    INSERT [dbo].[TABL1] ([A], [Y], [Z]) VALUES (3, N'Insert_1Y3', N'Insert_1Z3')
    INSERT [dbo].[TABL1] ([A], [Y], [Z]) VALUES (4, N'Insert_1Y4', N'Insert_1Z4')
    /****** Object:    Table [dbo].[TABL2]        Script Date: 05/27/2016 14:12:04 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[TABL2](
        [A] [int] NOT NULL,
        [B] [varchar](50) NULL,
        [C] [varchar](50) NULL,
        [AX] [int] NOT NULL,
        CONSTRAINT [PK_TABL2] PRIMARY KEY CLUSTERED
        (
            [A] ASC
        ) WITH (PAD_INDEX    = OFF, STATISTICS_NORECOMPUTE    = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS    = ON, ALLOW_PAGE_LOCKS    = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET ANSI_PADDING OFF
    GO
    INSERT [dbo].[TABL2] ([A], [B], [C], [AX]) VALUES (1, N'Insert_2B', N'Insert_2C1', 1)
    INSERT [dbo].[TABL2] ([A], [B], [C], [AX]) VALUES (2, N'Insert_2B2', N'Insert_2C2', 2)
    INSERT [dbo].[TABL2] ([A], [B], [C], [AX]) VALUES (3, N'Insert_2B3', N'Insert_2C3', 3)
    INSERT [dbo].[TABL2] ([A], [B], [C], [AX]) VALUES (4, N'Insert_2B4', N'Insert_2C4', 4)
    /****** Object:    Table [dbo].[TABL3]        Script Date: 05/27/2016 14:12:04 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[TABL3](
        [D] [int] IDENTITY(1,1) NOT NULL,
        [E] [nvarchar](50) NULL,
        [F] [nvarchar](50) NULL,
        [A] [int] NOT NULL,
        CONSTRAINT [PK_TABL3] PRIMARY KEY CLUSTERED
        (
            [D] ASC
        ) WITH (PAD_INDEX    = OFF, STATISTICS_NORECOMPUTE    = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS    = ON, ALLOW_PAGE_LOCKS    = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET IDENTITY_INSERT [dbo].[TABL3] ON
    INSERT [dbo].[TABL3] ([D], [E], [F], [A]) VALUES (1, N'Insert_3D1', N'Insert_3E1', 1)
    INSERT [dbo].[TABL3] ([D], [E], [F], [A]) VALUES (2, N'Insert_3D2', N'Insert_3E2', 2)
    INSERT [dbo].[TABL3] ([D], [E], [F], [A]) VALUES (3, N'Insert_3D3', N'Insert_3E3', 3)
    INSERT [dbo].[TABL3] ([D], [E], [F], [A]) VALUES (4, N'Insert_3D4', N'Insert_3E4', 4)
    SET IDENTITY_INSERT [dbo].[TABL3] OFF
    /****** Object:    ForeignKey [FK_TABL2_TABL1]        Script Date: 05/27/2016 14:12:04 ******/
    ALTER TABLE [dbo].[TABL2]    WITH CHECK ADD    CONSTRAINT [FK_TABL2_TABL1] FOREIGN KEY([AX])
    REFERENCES [dbo].[TABL1] ([A])
    GO
    ALTER TABLE [dbo].[TABL2] CHECK CONSTRAINT [FK_TABL2_TABL1]
    GO
    /****** Object:    ForeignKey [FK_TABL3_TABL2]        Script Date: 05/27/2016 14:12:04 ******/
    ALTER TABLE [dbo].[TABL3]    WITH CHECK ADD    CONSTRAINT [FK_TABL3_TABL2] FOREIGN KEY([A])
    REFERENCES [dbo].[TABL2] ([A])
    GO
    ALTER TABLE [dbo].[TABL3] CHECK CONSTRAINT [FK_TABL3_TABL2]
    GO
    
    /****** Object:    Table [dbo].[TABL4]        Script Date: 08/23/2016 14:26:23 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[TABL4](
        [A] [int] NOT NULL,
        [Y] [varchar](50) NULL,
        [Z] [varchar](50) NULL,
        [TimeStamp] [datetime] NULL,
        CONSTRAINT [PK_TABL4] PRIMARY KEY CLUSTERED
        (
            [A] ASC
        ) WITH (PAD_INDEX    = OFF, STATISTICS_NORECOMPUTE    = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS    = ON, ALLOW_PAGE_LOCKS    = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET ANSI_PADDING OFF
    GO
    INSERT [dbo].[TABL4] ([A], [Y], [Z], [TimeStamp]) VALUES (1, N'Insert_1Y', N'Insert_1Z', CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL4] ([A], [Y], [Z], [TimeStamp]) VALUES (2, N'Insert_1Y2', N'Insert_1Z2', CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL4] ([A], [Y], [Z], [TimeStamp]) VALUES (3, N'Insert_1Y3', N'Insert_1Z3', CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL4] ([A], [Y], [Z], [TimeStamp]) VALUES (4, N'Insert_1Y4', N'Insert_1Z4', CAST(0x0000A66B00EDAAD3 AS DateTime))
    /****** Object:    Table [dbo].[TABL5]        Script Date: 08/23/2016 14:26:23 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[TABL5](
        [A] [int] NOT NULL,
        [B] [varchar](50) NULL,
        [C] [varchar](50) NULL,
        [AX] [int] NOT NULL,
        [TimeStamp] [datetime] NULL,
        CONSTRAINT [PK_TABL5] PRIMARY KEY CLUSTERED
        (
            [A] ASC
        ) WITH (PAD_INDEX    = OFF, STATISTICS_NORECOMPUTE    = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS    = ON, ALLOW_PAGE_LOCKS    = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET ANSI_PADDING OFF
    GO
    INSERT [dbo].[TABL5] ([A], [B], [C], [AX], [TimeStamp]) VALUES (1, N'Insert_2B', N'Insert_2C1', 1, CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL5] ([A], [B], [C], [AX], [TimeStamp]) VALUES (2, N'Insert_2B2', N'Insert_2C2', 2, CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL5] ([A], [B], [C], [AX], [TimeStamp]) VALUES (3, N'Insert_2B3', N'Insert_2C3', 3, CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL5] ([A], [B], [C], [AX], [TimeStamp]) VALUES (4, N'Insert_2B4', N'Insert_2C4', 4, CAST(0x0000A66B00EDAAD3 AS DateTime))
    /****** Object:    Table [dbo].[TABL6]        Script Date: 08/23/2016 14:26:23 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[TABL6](
        [D] [int] NOT NULL,
        [E] [nvarchar](50) NULL,
        [F] [nvarchar](50) NULL,
        [A] [int] NOT NULL,
        [TimeStamp] [datetime] NULL,
        CONSTRAINT [PK_TABL6] PRIMARY KEY CLUSTERED
        (
            [D] ASC
        ) WITH (PAD_INDEX    = OFF, STATISTICS_NORECOMPUTE    = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS    = ON, ALLOW_PAGE_LOCKS    = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    INSERT [dbo].[TABL6] ([D], [E], [F], [A], [TimeStamp]) VALUES (1, N'Insert_3D1', N'Insert_3E1', 1, CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL6] ([D], [E], [F], [A], [TimeStamp]) VALUES (2, N'Insert_3D2', N'Insert_3E2', 2, CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL6] ([D], [E], [F], [A], [TimeStamp]) VALUES (3, N'Insert_3D3', N'Insert_3E3', 3, CAST(0x0000A66B00EDAAD3 AS DateTime))
    INSERT [dbo].[TABL6] ([D], [E], [F], [A], [TimeStamp]) VALUES (4, N'Insert_3D4', N'Insert_3E4', 4, CAST(0x0000A66B00EDAAD3 AS DateTime))
    /****** Object:    Default [DF_TABL4_TimeStamp]        Script Date: 08/23/2016 14:26:23 ******/
    ALTER TABLE [dbo].[TABL4] ADD    CONSTRAINT [DF_TABL4_TimeStamp]    DEFAULT (getdate()) FOR [TimeStamp]
    GO
    /****** Object:    Default [DF_TABL5_TimeStamp]        Script Date: 08/23/2016 14:26:23 ******/
    ALTER TABLE [dbo].[TABL5] ADD    CONSTRAINT [DF_TABL5_TimeStamp]    DEFAULT (getdate()) FOR [TimeStamp]
    GO
    /****** Object:    Default [DF_TABL6_TimeStamp]        Script Date: 08/23/2016 14:26:23 ******/
    ALTER TABLE [dbo].[TABL6] ADD    CONSTRAINT [DF_TABL6_TimeStamp]    DEFAULT (getdate()) FOR [TimeStamp]
    GO
    /****** Object:    ForeignKey [FK_TABL5_TABL4]        Script Date: 08/23/2016 14:26:23 ******/
    ALTER TABLE [dbo].[TABL5]    WITH CHECK ADD    CONSTRAINT [FK_TABL5_TABL4] FOREIGN KEY([AX])
    REFERENCES [dbo].[TABL4] ([A])
    GO
    ALTER TABLE [dbo].[TABL5] CHECK CONSTRAINT [FK_TABL5_TABL4]
    GO
    /****** Object:    ForeignKey [FK_TABL6_TABL5]        Script Date: 08/23/2016 14:26:23 ******/
    ALTER TABLE [dbo].[TABL6]    WITH CHECK ADD    CONSTRAINT [FK_TABL6_TABL5] FOREIGN KEY([A])
    REFERENCES [dbo].[TABL5] ([A])
    GO
    ALTER TABLE [dbo].[TABL6] CHECK CONSTRAINT [FK_TABL6_TABL5]
    GO
  4. コマンドプロンプトで以下のコマンドを実行し、本チュートリアルで使用するテスト用データベースを作成します。

    "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -S localhost\SQLExpress -E -i "C:\Users\[ユーザー名]\Documents\createTestTable.sql"

3. 本チュートリアルでの演習課題について

本チュートリアルでは、Visual Studio 2015 向け Open 棟梁テンプレート・ベースに付属のサンプルプログラムにデータメンテナンス画面自動生成機能で生成した画面・ロジックを追加・改修する形で演習を行います。サンプルプログラムの構成を図 3-1 に、チュートリアルの画面遷移図を図 3-2 に示します。

図 3-1 サンプルプログラムの構成図

図 3-2 サンプルプログラムの画面遷移図

4. 演習の準備

演習に先立ち、あらかじめ作成したデータベースの「D 層定義情報ファイル」および SQL ファイルを、Open 棟梁の D 層自動生成ツールを使用して生成しておきます。

4.1 SQL ファイルおよび Dao クラスの生成

  1. C:\root\programs\C#\Frameworks\DaoGen_Tool\bin\Debug\DaoGen_Tool.exe を実行し、D 層自動生成ツールを起動します。

  2. 以下のように値を設定し、「取得」ボタンをクリックします。

    • データプロバイダ: SQL Server Client
    • 接続文字列: Data Source=localhost\SQLExpress;Initial Catalog=Northwind;Integrated Security=true;
    • プルダウン: 概要情報
  3. 接続文字列等の情報に誤りがなければ、「DBMSのスキーマ情報の表示(概要情報)ダイアログ」が表示されます。

    本ダイアログが表示されたことを確認し、「閉じる」ボタンをクリックして、ダイアログを閉じます。

  4. 「テーブル一覧の取得」ボタンをクリックします。

    テーブル名称に関する注意を促すダイアログが表示されますが、「OK」ボタンをクリックして閉じてください。

  5. 本チュートリアルでは、「Categories」「Products」「TABL1 ~ TABL6」テーブルを使用します。これらのテーブル以外を選択して、「削除」ボタンをクリックします。

  6. リスト内の項目が、以下の図のようになったことを確認し、「ロード」ボタンをクリックします。

  7. 「D層定義情報を生成」ボタンが活性化されますので、出力エンコーディングとして「utf-8」を選択し、「D層定義情報を生成」ボタンをクリックします。

    D 層定義情報ファイルの保存ダイアログが表示されますので、C:\root\Info.csv にファイルを保存します。

  8. D 層定義情報ファイルが正常に生成できたことを示すダイアログが表示されますので、「OK」ボタンをクリックして閉じます。

  9. 「STEP2へ遷移」ボタンをクリックします。

  10. 「ステップ2」画面が表示されますので、以下のように値を設定し、「プログラムを生成する」ボタンをクリックします。

    • D 層定義情報ファイル: C:\root\Info.csv
    • ソーステンプレートフォルダ: C:\root\files\tools\DGenTemplates
    • 出力ファイル: C:\root
    • 上記以外はデフォルトのまま
  11. Dao、SQL ファイルが正常に生成できたことを示すダイアログが表示されますので、「OK」ボタンをクリックして閉じます。

  12. C:\root フォルダ以下に、Dao ファイル、SQL ファイルが生成されていることを確認します。

    【注意】Open 棟梁では、SQL ファイルとして、拡張子が .sql のファイルと、.xml のファイルがある。(詳しくは Open 棟梁の説明書をご覧ください)

4.2 SQL ファイルおよび Dao クラスの配置

4.1 節で作成した SQL ファイルおよび Dao ファイルを、Open 棟梁が規定するフォルダーに配置します。Open 棟梁が規定するフォルダーは、アプリケーション定義ファイル (app.config) で定義されており、自由にカスタマイズできます。本チュートリアルでは既定値である C:\root\files\resource\Sql に配置します。

C:\root\files\resource\Sql に、自動生成された SQL ファイル、 XML ファイルをコピーします。

<img src="./images/JOINTABLE/ScreenCapture_4_2_1.png" width="50%" >

5. 演習 1: データメンテナンス画面の生成

Open 棟梁のデータメンテナンス画面自動生成機能の利用方法 (ツールの使用方法、クラスのカスタマイズ方法、実行結果の確認方法) を、順を追って説明します。

5.1 データメンテナンス画面の生成

5.1.1 D 層定義情報の抽出

  1. C:\root\Info.csv をコピーし、C:\root\Info2.csv を作成します。

  2. ここでは Categories テーブルと Products テーブルを使用するため、以下のように、TABL1 ~ TABL6 テーブルの定義情報を削除します。

    Table name, column information -
    Categories,CategoryID,
    ,CategoryName,Description,Picture,
    Products,ProductID,
    ,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued,
    

5.1.2 結合 SQL ファイルの作成

  1. C:\root\files\resource\Sql フォルダーに、新規に XML ファイルを作成し、ファイル名を DaoCategories_Products_JOIN_S2_Select.xml とします。

  2. DaoCategories_Products_JOIN_S2_Select.xml を以下のように定義します。

    <?xml version="1.0" encoding="UTF-8"?>
    <ROOT>
    SELECT Categories.CategoryID [Categories.CategoryID],
            Categories.CategoryName [Categories.CategoryName],
            Categories.Description [Categories.Description],
            Products.CategoryID [Products.CategoryID],
            Products.ProductID [Products.ProductID],
            Products.ProductName [Products.ProductName],
            Products.QuantityPerUnit [Products.QuantityPerUnit],
            Products.ReorderLevel [Products.ReorderLevel],
            Products.UnitPrice [Products.UnitPrice],
            Products.UnitsInStock [Products.UnitsInStock],
            Products.UnitsOnOrder [Products.UnitsOnOrder]
    FROM Categories,Products
    <WHERE>
    WHERE Categories.CategoryID = Products.CategoryID
            <IF>AND Categories.CategoryID = @Categories_CategoryID<ELSE>AND Categories.CategoryID IS NULL</ELSE></IF>
            <IF>AND Categories.CategoryName = @Categories_CategoryName<ELSE>AND Categories.CategoryName IS NULL</ELSE></IF>
            <IF>AND Categories.Description= @Categories_Description<ELSE>AND Categories.Description IS NULL</ELSE></IF>
            <IF>AND Products.CategoryID= @Products_CategoryID<ELSE>AND Products.CategoryID IS NULL</ELSE></IF>
            <IF>AND Products.ProductID = @Products_ProductID<ELSE>AND Products.ProductID IS NULL</ELSE></IF>
            <IF>AND Products.ProductName = @Products_ProductName<ELSE>AND Products.ProductName IS NULL</ELSE></IF>
            <IF>AND Products.QuantityPerUnit = @Products_QuantityPerUnit<ELSE>AND Products.QuantityPerUnit IS NULL</ELSE></IF>
            <IF>AND Products.ReorderLevel = @Products_ReorderLevel<ELSE>AND Products.ReorderLevel IS NULL</ELSE></IF>
            <IF>AND Products.UnitPrice = @Products_UnitPrice<ELSE>AND Products.UnitPrice IS NULL</ELSE></IF>
            <IF>AND Products.UnitsInStock = @Products_UnitsInStock<ELSE>AND Products.UnitsInStock IS NULL</ELSE></IF>
            <IF>AND Products.UnitsOnOrder = @Products_UnitsOnOrder<ELSE>AND Products.UnitsOnOrder IS NULL</ELSE></IF>
    </WHERE>
    </ROOT>

    【注意】
    DPQuery_Tool を使用して、結合テーブルに対するデータメンテナンス画面を生成する場合、以下のようなルールがあります。

    • エイリアス名
      テーブル結合を行う場合、エイリアス名は「[テーブル名].[列名]」である必要があります。なお、テーブル名が空白文字を含む場合は、空白文字をアンダースコアに置き換える必要があります。
    • TimeStamp 列の扱い
      結合クエリに「TimeStamp」という名前の列があった場合、データメンテナンス画面には表示されず、条件検索のみに使用されます。また、楽観的排他制御を行う場合、データメンテナンス画面が扱うテーブルにはすべてタイムスタンプを保持する列が必要です。また、その列名は同じである必要があります。楽観的排他制御を含むデータメンテナンス画面の生成方法については、5.3 節で説明します。

5.1.3 データメンテナンス画面の生成

  1. C:\root\programs\C#\Frameworks\Tools\DPQuery_Tool\bin\Debug\DPQuery_Tool.exe を起動します。

  2. DPQuery_Tool が起動し、下の図のような画面が表示されることを確認します。

  3. 以下のように設定し、「接続」ボタンをクリックします。

    • データプロバイダ: SQL Server - sqlClient
    • 接続文字列: Data Source=localhost\sqlexpress;Initial Catalog=Northwind;Integrated Security=True;

    DBへの接続に成功し、「接続」ボタンが非活性化し、代わりに「切断」ボタン、「クエリ実行」ボタンが活性化されたことを確認します。

  4. 「開く」ボタンをクリックします。

  5. ファイルを開くダイアログで、4.2.1 項で作成した DaoCategories_Products_JOIN_S2_Select.xml を選択します。

  6. ツール画面中央に、DaoCategories_Products_JOIN_S2_Select.xml ファイルの内容が表示されることを確認し、「クエリ実行」ボタンをクリックします。

  7. 以下の図のようなメッセージボックスが表示され、クエリの実行に成功したことを確認し、「OK」ボタンをクリックします。

  8. 「結果Table1」画面が開き、クエリの実行結果が表示されることを確認し、「Generate」ボタンをクリックします。

  9. 「結合SELECT文をするための画面を生成する」画面が表示されるので、以下のように設定し、「ステップ2」タブをクリックします。

    • D層定義情報ファイル: C:\root\Info2.csv
    • ソース テンプレート ファイル: C:\root\files\tools\DGenTemplates
    • 出力ファイル: C:\root\files\AutoGeneratedFiles
    • 上記以外はデフォルトのまま
  10. データプロバイダとして、「SQL Server Client」が選択されていることを確認し、「- Dao・SQL、DTOファイルを生成します -1」ボタンをクリックします。

  11. 以下の図のようなメッセージボックスが表示され、画面の生成に成功したことを確認し、「OK」ボタンをクリックします。

  12. 出力先として指定したフォルダーに、データメンテナンス画面が生成されていることを確認します。

5.1.4 データメンテナンス画面の配置

  1. C:\root\programs\C#\Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln を開きます。

  2. 4.2.2 項で生成したデータメンテナンス画面をすべてコピーします。

  3. ソリューション エクスプローラーで、Aspx\sample\3Tier フォルダーを右クリックし、「貼り付け」を選択します。

  4. 3Tier フォルダーに、データメンテナンス画面が追加されたことを確認します。

    【注意】
    DPQuery_Tool のデータメンテナンス画面自動生成機能を使用すると、HTML コードを記述する ASPX ファイルと、そのコードビハインドを記述する C# ファイルが生成されます。Web アプリケーション プロジェクトの場合、これらの他に Visual Studio のデザイナーが出力するコードである「.designer.cs」というファイルが必要になります。Open 棟梁テンプレート・ベースに含まれる Web アプリケーションのサンプルプロジェクトも Web アプリケーション プロジェクトのため、この「.designer.cs」ファイルを追加する必要があります。

  5. ソリューション エクスプローラーで、プロジェクト名の部分を右クリックし、「Web アプリケーションに変換」を選択します。

  6. 以下の図のような確認ダイアログが表示されますので、「はい」をクリックします。

  7. 3Tier フォルダーの下に、「.designer.cs」ファイルが生成されていることを確認します。

  8. ソリューション エクスプローラーで、Aspx\sample\3Tier\Categories_Products_JOIN_Screen_ConditionalSearch.aspx を右クリックし、「スタート ページに設定」を選択します。

  9. アプリケーションをビルドします。

5.2 データメンテナンス画面の動作確認

5.2.1 ASP.NET 状態サービスの開始

  1. スタートメニューの「プログラムとファイルの検索」ボックスから、 services.msc を実行します。

  2. サービス画面から「ASP.NET 状態サービス」を右クリックし、「開始」を選択します。

    【注意】
    初期状態では、「ASP.NET 状態サービス」のスタートアップの種類は「無効」になっています。このため、ASP.NET 状態サービスのプロパティ画面から、スタートアップの種類を「手動」などに変える必要があります。

5.2.2 条件検索画面の動作確認

  1. Visual Studio で、アプリケーションをデバッグ実行します。

  2. ブラウザが起動し、ログイン画面が表示されますので、以下のように値を入力し、「ログイン」ボタンを押下します。

    • ユーザID: 空でない任意の文字列
    • パスワード: 任意の文字列 (空でもよい)
  3. 以下の図のような画面が表示されることを確認します。

  4. ここで、検索条件を入力し、「Search Result」ボタンをクリックすると、画面の下部に結果が表示されます。この画面の仕様は以下のとおりです。

    • 何も入力しなかった場合: 全件検索
    • テキストボックスに検索条件を入力した場合: 入力した条件による AND 検索

    まずは、何も入力せずに「Search Result」ボタンをクリックします。

  5. 全件検索の結果が表示されることを確認します。

    【メモ】
    上の図のように、主キーとして設定されている列 (今回のサンプルでは、Catetories テーブルの CategoryID 列および Products テーブルの ProductID 列) はグレーアウトされ、編集不可となります。

  6. 次に、検索条件として、CategoryID に 1 を入力して、「Search Result」ボタンをクリックします。

  7. CategoryID 列が 1 のレコードのみが表示されることを確認します。

  8. 次に、AND 検索の確認として、CategoryID に 1 を、ProductID に 2 を入力して、「Search Result」ボタンをクリックします。

  9. AND 検索が実行され、CategoryID が 1 で、かつ ProductID が 2 のレコードのみが表示されることを確認します。

5.2.3 詳細画面の動作確認

  1. 4.3.2 項の手順を実行後、結果セットの「Select」ボタンをクリックします。

  2. 以下の図のような画面が表示されることを確認し、「Edit Record」ボタンをクリックします。(初期状態では、図のようにすべての項目が編集不可となります)

  3. 主キー列以外が編集可能になったことを確認し、いくつかの項目を編集し、「Update Record」ボタンをクリックします。

  4. データベースの更新に成功すると、以下の図のように「n Table Data Updated Successfully」と表示されます。

    【メモ】
    ここで、内部的には Products テーブルに対する更新と、Categories テーブルに対する更新がそれぞれ行われます。このことは、Open 棟梁の SQL トレースログでも確認できます。

    [2016/12/02 11:59:39,908],[INFO ],[8],22,0,[commandText]: -- DaoProducts_S3_Update -- 2016/12/1 日立 太郎 UPDATE [Products] SET [ProductName] = @Set_ProductName_forUPD, [CategoryID] = @Set_CategoryID_forUPD, [QuantityPerUnit] = @Set_QuantityPerUnit_forUPD, [UnitPrice] = @Set_UnitPrice_forUPD, [UnitsInStock] = @Set_UnitsInStock_forUPD, [UnitsOnOrder] = @Set_UnitsOnOrder_forUPD, [ReorderLevel] = @Set_ReorderLevel_forUPD WHERE [ProductID] = @ProductID    [commandParameter]:ProductID=2,CategoryID=1,Set_ProductName_forUPD=Chang,Set_CategoryID_forUPD=1,Set_QuantityPerUnit_forUPD=24 - 12 oz bottles,Set_UnitPrice_forUPD=20,Set_UnitsInStock_forUPD=17,Set_UnitsOnOrder_forUPD=40,Set_ReorderLevel_forUPD=25,
    [2016/12/02 11:59:39,924],[INFO ],[8],3,0,[commandText]: -- DaoCategories_S3_Update -- 2016/12/1 日立 太郎 UPDATE [Categories] SET [CategoryName] = @Set_CategoryName_forUPD, [Description] = @Set_Description_forUPD WHERE [CategoryID] = @CategoryID    [commandParameter]:ProductID=2,CategoryID=1,Set_CategoryName_forUPD=Beverages,Set_Description_forUPD=Soft drinks, coffees, teas, beers, and ales,

    また、「Delete Record」ボタンをクリックすると、同様に Products テーブルと Categories テーブルへの Delete 文が実行されます。ただし、結合テーブルの親テーブルに外部キー制約を設定している場合、親テーブルを先に削除しようとしたり、当該外部キーを参照している子テーブルのレコードがまだ残っている場合、親テーブルのレコード削除時にエラーが発生します。レコードの削除を行う場合は、設定されている外部キー制約や、自動生成されたプログラムをよく確認し、必要であればプログラムのカスタマイズを検討してください。なお、削除処理のカスタマイズ方法については 6.1 節で紹介しています。

5.2.4 バッチ更新画面の動作確認

  1. ソリューション エクスプローラーで、Aspx\sample\3Tier\Categories_Products_JOIN_Screen_SearchAndUpdate.aspx を右クリックし、「スタート ページに設定」を選択します。

  2. アプリケーションをデバッグ実行します。

  3. ブラウザが起動し、ログイン画面が表示されますので、以下のように値を入力し、「ログイン」ボタンを押下します。

    • ユーザID: 空でない任意の文字列
    • パスワード: 任意の文字列 (空でもよい)
  4. 以下の図のような画面が表示されることを確認します。

  5. ここで、検索条件を入力し、「Search Record」ボタンをクリックすると、画面の下部に結果が表示されます。この画面の仕様は以下のとおりです。

    • 何も入力しなかった場合: 全件検索
    • テキストボックスに検索条件を入力した場合: 入力した条件による AND 検索

    まずは、何も入力せずに「Search Record」ボタンをクリックします。

  6. 以下の図のように、検索結果が表示されることを確認します。レコードの値を更新する場合は、テキストボックスに新しい値を入力して「Update」リンクをクリックします。レコードを削除する場合は、削除したいレコードの「Delete」リンクをクリックします。

    【メモ】
    この段階では、まだデータベースへは変更内容は反映されていません。次の「Update the Result Set Using Batch Update」ボタンにより、変更内容がデータベースに反映されます。

  7. 「Update the Result Set Using Batch Update」ボタンが活性化されたことを確認し、「Update the Result Set Using Batch Update」ボタンをクリックします。

    【メモ】
    4.3.3 項と同様、ここでも内部的には Products テーブルに対する更新と、Categories テーブルに対する更新がそれぞれ行われます。このことは、Open 棟梁の SQL トレースログでも確認できます。

6. 演習 2: 自動生成された画面のカスタマイズ

前章では、データメンテナンス画面の基本的な使い方について紹介しました。本章では、自動生成された画面やロジックをカスタマイズする方法について紹介します。

6.1 削除処理のカスタマイズ

本節では、結合テーブルに対して、自動生成された削除処理をカスタマイズする方法を紹介します。削除処理を行う場合、開発者はそれぞれのテーブルの主キーと外部キーの関連 (どちらが親テーブルで、どちらが子テーブルか) をよく確認した上で、削除処理の順序を決定する必要があります。

本節では、テスト用テーブルのキーの関連性にもとづいて、自動生成された削除処理をカスタマイズする方法を紹介します。

本節で使用するテーブルの関連を図 6-1 に示します。TABL3 テーブルの A 列は TABL2 テーブルの A 列を参照し、TABL2 テーブルの AX 列は TABL1 テーブルの A 列を参照しています。つまり、TABL1 テーブルと TABL2 テーブルでは、TABL1 テーブルが親であり、TABL2 テーブルが子となります。また、TABL2 テーブルと TABL3 テーブルでは、TABL2 テーブルが親であり、TABL3 テーブルが子となります。

図 6-1 テスト用テーブルの関連図 (ER図)

6.1.1 D 層定義情報の抽出

  1. C:\root\Info.csv をコピーし、C:\root\Info3.csv を作成します。

  2. ここでは TABL1 ~ TABL3 テーブルを使用するため、以下のように、Categories テーブル、Products テーブル、TABL4 ~ TABL6 テーブルの定義情報を削除します。

    Table name, column information -
    TABL1,A,
    ,Y,Z,
    TABL2,A,
    ,B,C,AX,
    TABL3,D,
    ,E,F,A,

6.1.2 結合 SQL ファイルの作成

  1. C:\root\files\resource\Sql フォルダーに、新規に XML ファイルを作成し、ファイル名を DaoTABL1_TABL2_TABL3_JOIN_S2_Select.xml とします。

  2. DaoTABL1_TABL2_TABL3_JOIN_S2_Select.xml を以下のように定義します。

    <?xml version="1.0" encoding="UTF-8"?>
    <ROOT>
    SELECT TABL1.A [TABL1.A],
            TABL1.Y [TABL1.Y],
            TABL1.Z [TABL1.Z],
            TABL2.A [TABL2.A],
            TABL2.B [TABL2.B],
            TABL2.C [TABL2.C],
            TABL2.AX [TABL2.AX],
            TABL3.D [TABL3.D],
            TABL3.E [TABL3.E],
            TABL3.F [TABL3.F],
            TABL3.A [TABL3.A]
    FROM TABL1, TABL2, TABL3
    <WHERE>
    WHERE TABL1.A = TABL2.AX
            AND TABL2.A = TABL3.A
            <IF>AND TABL1.A = @TABL1_A<ELSE>AND TABL1.A IS NULL</ELSE></IF>
            <IF>AND TABL1.Y = @TABL1_Y<ELSE>AND TABL1.Y IS NULL</ELSE></IF>
            <IF>AND TABL1.Z = @TABL1_Z<ELSE>AND TABL1.Z IS NULL</ELSE></IF>
            <IF>AND TABL2.A = @TABL2_A<ELSE>AND TABL2.A IS NULL</ELSE></IF>
            <IF>AND TABL2.B = @TABL2_B<ELSE>AND TABL2.B IS NULL</ELSE></IF>
            <IF>AND TABL2.C = @TABL2_C<ELSE>AND TABL2.C IS NULL</ELSE></IF>
            <IF>AND TABL2.AX = @TABL2_AX<ELSE>AND TABL2.AX IS NULL</ELSE></IF>
            <IF>AND TABL3.D = @TABL3_D<ELSE>AND TABL3.D IS NULL</ELSE></IF>
            <IF>AND TABL3.E = @TABL3_E<ELSE>AND TABL3.E IS NULL</ELSE></IF>
            <IF>AND TABL3.F = @TABL3_F<ELSE>AND TABL3.F IS NULL</ELSE></IF>
            <IF>AND TABL3.A = @TABL3_A<ELSE>AND TABL3.A IS NULL</ELSE></IF>
    </WHERE>
    </ROOT>

6.1.3 データメンテナンス画面の生成および配置

  1. 4.2.2 項および 4.2.3 項を参考に、DPQuery_Tool を使用して、DaoTABL1_TABL2_TABL3_JOIN_S2_Select.xml の結果セットをもとにしたデータメンテナンス画面を生成します。生成した画面は、Aspx\sample\3Tier フォルダーに配置します。

  2. ソリューション エクスプローラーで、WebForms_Sample を右クリックし、「Web アプリケーションに変換」を選択し、「.designer.cs」ファイルが生成されることを確認します。

6.1.4 削除処理のカスタマイズ

  1. ソリューション エクスプローラーで、TABL1_TABL2_TABL3_JOIN_Screen_Detail.aspx.cs を開きます。

  2. コードエディター上部のドロップダウンリストから、UOC_btnDelete_Click を選択します。

  3. UOC_btnDelete_Click メソッドが表示されることを確認します。さらに、UOC_btnDelete_Click メソッドの中で、「Delete the data from the XXXX table」と名前のつけられたコードブロックを確認します。

    【メモ】
    この図では、上記の「XXXX」の部分が「TABL1」「TABL2」「TABL3」の順番になっています。これは、この順番にレコードの削除処理が実行されることを示しています。しかし、図 6-1 に示しましたように、TABL1 は TABL2 の親テーブルのため、基本的には子テーブルから順番に削除する必要があります。 また、既定ではレコードの削除処理が順番に行われます。実際の開発の場面では、「その親レコードを参照している子レコードが残っていないことを確認してから、親レコードを削除する」などの要件がある場合があります。この場合は、「Delete the data from the XXXX table」のコードブロックの間に、「削除しようとしている親レコードを参照している子レコードの存在チェック」を追加する必要があります。本チュートリアルでは、コードをわかりやすくするため、削除の順番を変えるだけに留めます。

  4. 削除処理の実行順序を、「TABL3」「TABL2」「TABL1」(子テーブルから親テーブルへ) になるように、コードを修正します。

  5. 同様に、TABL1_TABL2_TABL3_JOIN_Screen_SearchAndUpdate.aspx.cs の「UOC_btnBatUpd_Click」メソッドも、削除処理の順番が「TABL3」「TABL2」「TABL1」になるようにコードを修正します。

6.1.5 動作確認

  1. 4.3 節を参考に、TABL1_TABL2_TABL3_JOIN_Screen_ConditionalSearch.aspx をスタートページに指定し、デバッグ実行します。

  2. 任意のレコードを検索し、「Delete Record」をクリックし、「3 Data is Deleted from the table Successfully」のメッセージが表示されることを確認します。

  3. SQL トレースログを開き、「TABL3」「TABL2」「TABL1」の順番に削除処理が実行されていることを確認します。

    [2016/12/05 16:17:01,891],[INFO ],[6],21,0,[commandText]: -- DaoTABL3_S4_Delete -- 2016/12/5 日立 太郎 DELETE FROM [TABL3] WHERE [D] = @D    [commandParameter]:D=1,TABL2_A=1,TABL1_A=1,
    [2016/12/05 16:17:01,910],[INFO ],[6],1,0,[commandText]: -- DaoTABL2_S4_Delete -- 2016/12/5 日立 太郎 DELETE FROM [TABL2] WHERE [A] = @A    [commandParameter]:TABL3_D=1,A=1,TABL1_A=1,
    [2016/12/05 16:17:01,928],[INFO ],[6],1,0,[commandText]: -- DaoTABL1_S4_Delete -- 2016/12/5 日立 太郎 DELETE FROM [TABL1] WHERE [A] = @A    [commandParameter]:TABL3_D=1,TABL2_A=1,A=1,

6.2 楽観的排他制御を含むデータメンテナンス画面の生成

楽観的排他制御とは、テーブルの排他制御の一つです。レコードを更新する直前に、他のユーザーによってそのレコードが先に更新されていないかをチェックし、更新されていなければ更新処理を続行し、更新されていれば更新処理をキャンセルする仕組みです。他のユーザーによってそのレコードが更新されたことを知るために、タイムスタンプを使用するケースが多いです。

タイムスタンプを使用した、楽観的排他制御の仕組みを図 6-2 に示します。

図 6-2 楽観的排他制御の仕組み

Open 棟梁には、この楽観的排他制御を含む、データメンテナンス画面を生成できます。本節では、その方法を紹介します。

本節で使用するテーブルの関連を図 6-3 に示します。大きくは図 6-1 と変わりませんが、各テーブルに、タイムスタンプ値を格納するための「TimeStamp」列がある点が異なります。

図 6-3 テスト用テーブルの関連図 (ER図)

6.2.1 D 層定義情報の抽出

  1. C:\root\Info.csv をコピーし、C:\root\Info4.csv を作成します。

  2. ここでは TABL4 ~ TABL6 テーブルを使用するため、以下のように、Categories テーブル、Products テーブル、TABL1 ~ TABL3 テーブルの定義情報を削除します。

    Table name, column information -
    TABL4,A,
    ,Y,Z,TimeStamp,
    TABL5,A,
    ,B,C,AX,TimeStamp,
    TABL6,D,
    ,E,F,A,TimeStamp,

6.2.2 結合 SQL ファイルの作成

  1. C:\root\files\resource\Sql フォルダーに、新規にXMLファイルを作成し、ファイル名を DaoTABL4_TABL5_TABL6_JOIN_S2_Select.xml とします。

  2. DaoTABL4_TABL5_TABL6_JOIN_S2_Select.xml を以下のように定義します。

    <?xml version="1.0" encoding="UTF-8"?>
    <ROOT>
    SELECT TABL4.A [TABL4.A],
            TABL4.Y [TABL4.Y],
            TABL4.Z [TABL4.Z],
            TABL4.TimeStamp [TABL4.TimeStamp],
            TABL5.A [TABL5.A],
            TABL5.B [TABL5.B],
            TABL5.C [TABL5.C],
            TABL5.AX [TABL5.AX],
            TABL5.TimeStamp [TABL5.TimeStamp],
            TABL6.D [TABL6.D],
            TABL6.E [TABL6.E],
            TABL6.F [TABL6.F],
            TABL6.A [TABL6.A],
            TABL6.TimeStamp [TABL6.TimeStamp]
    FROM TABL4, TABL5, TABL6
    <WHERE>
    WHERE TABL4.A = TABL5.AX
            AND TABL5.A = TABL6.A
            <IF>AND TABL4.A = @TABL4_A<ELSE>AND TABL4.A IS NULL</ELSE></IF>
            <IF>AND TABL4.Y = @TABL4_Y<ELSE>AND TABL4.Y IS NULL</ELSE></IF>
            <IF>AND TABL4.Z = @TABL4_Z<ELSE>AND TABL4.Z IS NULL</ELSE></IF>
            <IF>AND TABL5.A = @TABL5_A<ELSE>AND TABL5.A IS NULL</ELSE></IF>
            <IF>AND TABL5.B = @TABL5_B<ELSE>AND TABL5.B IS NULL</ELSE></IF>
            <IF>AND TABL5.C = @TABL5_C<ELSE>AND TABL5.C IS NULL</ELSE></IF>
            <IF>AND TABL5.AX = @TABL5_AX<ELSE>AND TABL5.AX IS NULL</ELSE></IF>
            <IF>AND TABL6.D = @TABL6_D<ELSE>AND TABL6.D IS NULL</ELSE></IF>
            <IF>AND TABL6.E = @TABL6_E<ELSE>AND TABL6.E IS NULL</ELSE></IF>
            <IF>AND TABL6.F = @TABL6_F<ELSE>AND TABL6.F IS NULL</ELSE></IF>
            <IF>AND TABL6.A = @TABL6_A<ELSE>AND TABL6.A IS NULL</ELSE></IF>
    </WHERE>
    </ROOT>

6.2.3 データメンテナンス画面の生成および配置

  1. 4.2.2 項を参考に、DPQuery_Tool を使用して、DaoTABL4_TABL5_TABL6_JOIN_S2_Select.xml の結果セットをもとにしたデータメンテナンス画面を生成します。ここで、楽観的排他制御のための処理も自動生成させるため、「ステップ2」タブで以下のように設定して、「- Dao・SQL、DTOファイルを生成する -1」ボタンをクリックします。

    • タイムスタンプ列名: TimeStamp
    • 更新方法: SYSDATETIME()
    • タイムスタンプ必須: チェックあり
  2. 4.2.3 項を参考に、生成した画面を Aspx\sample\3Tier フォルダーに配置します。

  3. ソリューション エクスプローラーで、WebForms_Sample を右クリックし、「Webアプリケーションに変換」を選択し、「.designer.cs」ファイルが生成されることを確認します。

6.2.4 更新処理のカスタマイズ

  1. ソリューション エクスプローラーで、TABL4_TABL5_TABL6_JOIN_Screen_SearchAndUpdate.aspx.cs を開きます。

  2. コードエディター上部のドロップダウンリストから、UOC_btnBatUpd_Click を選択します。

  3. 以下のコードを検索します。

    //Timestamp column
    parameterValue.AndEqualSearchConditions.Add("TimeStamp", "");

    【メモ】
    このコードは、TimeStamp 列を検索条件に追加しているコードです。このコードは、TABL4、TABL5、TABL6 の各テーブルの更新処理の中にそれぞれ実装されています。このため、その TimeStamp 列がどのテーブルの TimeStamp 列なのかを区別させる必要があります。

  4. 上記の部分を、以下のように修正します。(それぞれ、[テーブル名]_TimeStamp となるように修正します)

    • TABL4 更新部分

      //Timestamp column
      parameterValue.AndEqualSearchConditions.Add("TABL4_TimeStamp", "");
    • TABL5 更新部分

      //Timestamp column
      parameterValue.AndEqualSearchConditions.Add("TABL5_TimeStamp", "");
    • TABL6 更新部分

      //Timestamp column
      parameterValue.AndEqualSearchConditions.Add("TABL6_TimeStamp", "");

6.2.5 動作確認

  1. 4.3 節を参考に、TABL4_TABL5_TABL6_JOIN_Screen_ConditionalSearch.aspx をスタートページに指定し、デバッグ実行します。

  2. 任意のレコードの値を更新し、「Update Record」ボタンをクリックし、「3 Data is Deleted from the table Successfully」のメッセージが表示されることを確認します。

  3. 次に、楽観的排他制御をテストするため、ブラウザを 2 つ起動し、同じレコードを参照させます。

  4. 片方のブラウザで値を更新します。

  5. もう片方のブラウザで値を更新します。ただし、すでにそのレコードは他のブラウザ (ユーザー) によって更新されていますので、楽観的排他制御により、レコードが更新されないことを確認します。

6.3 値の関連チェックの実装

業務要件によっては、更新する値の関連チェックが必要になる場合があります。たとえば、「開始日」「終了日」のカラムがあった場合、「終了日は開始日よりも後でなければならない」などです。本節では、自動生成されたメンテナンス画面に、値の関連チェックを追加する方法を紹介します。

  1. ソリューション エクスプローラーで、AppCode\sample\Business フォルダーを右クリックし、「追加」-「クラス」を選択します。

  2. My3TierEngine.cs クラスを追加します。

  3. Open 棟梁の各クラスを参照するため、以下のコードを追加します

    // 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;
    
    // Parts
    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;
    
    // B 層クラス
    using WebForms_Sample.AppCode.sample.Business;
  4. Open 棟梁は、既定では Open 棟梁が提供している _3TierEngine クラスを使用して、データメンテナンスを行います。ここで、先ほど作成した My3TierEngine クラスに、_3TierEngine クラスを継承させます。

    public class My3TierEngine : _3TierEngine
    {
    }
  5. My3TierEngine クラスを以下のように実装します。ポイントは、値の関連チェックを実装するための UOC_RelatedCheck メソッドです。このメソッドに関連チェックロジックを実装することで、テーブル更新時に、値の関連チェックを実行できます。(なお、本チュートリアルでは、関連チェックの実装箇所のみ示し、実際のロジックは実装しません)

    public class My3TierEngine : _3TierEngine
    {
            /// <summary>Constructor</summary>
            public My3TierEngine()
            {
                    // TODO: Add the constructor logic here
            }
    
            #region Fixed execution
            /// <summary>Call base</summary>
            /// <param name="parameterValue">Argument class</param>
            protected override void UOC_SelectRecord(_3TierParameterValue parameterValue)
            {
                    base.UOC_SelectRecord(parameterValue);
            }
            /// <summary>Call base</summary>
            /// <param name="parameterValue">Argument class</param>
            protected override void UOC_UpdateRecordDM(_3TierParameterValue parameterValue)
            {
                    base.UOC_UpdateRecordDM(parameterValue);
            }
            /// <summary>Call base</summary>
            /// <param name="parameterValue"> Argument class </param>
            protected override void UOC_DeleteRecordDM(_3TierParameterValue parameterValue)
            {
                    base.UOC_DeleteRecordDM(parameterValue);
            }
            /// <summary>Call base</summary>
            /// <param name="parameterValue"> Argument class </param>
            protected override void UOC_BatchUpdateDM(_3TierParameterValue parameterValue)
            {
                    base.UOC_BatchUpdateDM(parameterValue);
            }
            #endregion
    
            /// <summary> Work code class for three layer data bind related check </summary>
            /// <param name="parameterValue"> Argument class </param>
            protected override void UOC_RelatedCheck(_3TierParameterValue parameterValue)
            {
                    // TODO: ここに、値の関連チェックを実装する
            }
    }
  6. UOC_RelatedCheck メソッドにブレークポイントを置きます

  7. TABL1_TABL2_TABL3_JOIN_Screen_Detail.aspx.cs を開き、UOC_btnUpdate_Click メソッドおよび UOC_btnDelete_Click メソッドの中で、_3TierEngine クラスを参照している箇所を検索します。

    // B layer Initialize
    _3TierEngine b = new _3TierEngine();
  8. 上記の部分を、以下のように修正します。(参照するクラスを My3TierEngine にします)

    // B layer Initialize
    My3TierEngine b = new My3TierEngine();
  9. TABL1_TABL2_TABL3_JOIN_Screen_ConditionalSearch.aspx をスタートページに設定し、アプリケーションをデバッグします。

  10. レコード更新時に、ブレークポイントを設置した UOC_RelatedCheck メソッドでブレークすることを確認します。

Clone this wiki locally