WebSurfer's Home

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

EDM にデータアノテーション属性を付与

by WebSurfer 2017年5月21日 15:10

Microsoft のチュートリアル「10 行でズバリ!! ASP.NET MVC を構成する各コンポーネントとネーミング ルール (C#)」のように、既存の SQL Server データベースから Entity Data Model (EDM) を生成して ASP.NET MVC アプリで使用する場合、ユーザー入力を検証するためのデータアノテーション属性をどのように付与できるかを書きます。

Visual Studio で生成した EDM

上の画像は、SQL Server 2008 Express のデータベース AdventureWorksLT をベースに、Visual Studio 2015 + EF6 で生成した EDM (Model1.edmx) です。(注:Visual Studio 2010 + EF4 で生成した EDM は内容が異なりますが、データアノテーション属性を付与する方法は同じです)

生成した EDM をベースに、上に紹介した「10 行でズバリ!!」チュートリアルと同様に、Visual Studio のスキャフォールディング機能を利用して、Address テーブルを表示・編集する ASP.NET MVC アプリの Controller と View を一式自動生成する場合を例に考えます。

自動生成された EDM で Address テーブルを表す Model のコードは、上の画像で示すように Address.cs にあります。そのコードは以下の通りです(説明に不要な部分は省略しています)。

namespace AdventureWorksLT
{
    using System;
    using System.Collections.Generic;
    
    public partial class Address
    {
        //・・・コンストラクタ(省略)・・・
        
        public int AddressID { get; set; }
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string City { get; set; }
        public string StateProvince { get; set; }
        public string CountryRegion { get; set; }
        public string PostalCode { get; set; }
        public System.Guid rowguid { get; set; }
        public System.DateTime ModifiedDate { get; set; }
    
        //・・・ナビゲーションプロパティ(省略)・・・
    }
}

これに手を加えればよさそうに思えますが、それは NG です。何故なら、コードのコメントに書いてあるように、"このファイルを手動で変更すると、アプリケーションで予期しない動作が発生する可能性があります。このファイルに対する手動の変更は、コードが再生成されると上書きされます" ということだからです。

ではどうするかですが、Microsoft の文書「Validation with the Data Annotation Validators (C#)」の「Using Data Annotation Validators with the Entity Framework」のセクションに書いてある方法を取るのがよさそうです。(日本語版は機械翻訳なので英文を読むことをお勧めします)

TechNet の記事を読めばこれ以降の説明は不要かもしれませんが、記事がリンク切れになったりすると困るので、上の Address クラスの場合を例に方法を書いておきます。

具体的には以下のようなコードを EDM とは別の場所にクラスファイルを追加してそれに含めます。上の画像のソリューションエクスプローラの AddressMetaData.cs がそのクラスファイルです。

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace AdventureWorksLT
{
    [MetadataType(typeof(AddressMetaData))]
    public partial class Address
    {

    }

    public class AddressMetaData
    {
        [Display(Name = "住所1")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        public object AddressLine1 { get; set; }

        [Display(Name = "住所2")]
        public object AddressLine2 { get; set; }

        [Display(Name = "街")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        [StringLength(10, ErrorMessage = "{0} は {1} 以内。")]
        public object City { get; set; }

        [Display(Name = "州")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        public object StateProvince { get; set; }

        [Display(Name = "国名")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        public object CountryRegion { get; set; }

        [Display(Name = "郵便番号")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        public object PostalCode { get; set; }

        [Display(Name = "GUID")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        public object rowguid { get; set; }

        [Display(Name = "更新日")]
        [Required(ErrorMessage = "{0} は必須入力です")]
        public object ModifiedDate { get; set; }
    }
}

上のコードで AddressMetaData が TechNet の記事で言うメタデータクラスです。それにプロキシプロパティを定義して必要なデータアノテーション属性を付与しています。

TechNet の記事にも書いてありますが、プロキシプロパティの型は自動生成された Address クラスのプロパティの型と同じである必要はないそうです(同じでも OK ですが)。上のコードでは TechNet の記事にならってプロキシプロパティの型は Object 型にしています。

自動生成された Address クラスは partial として定義されているところに注目してください。partial なので、上のコードのように別のクラスファイルに Address クラスを定義してそれに MetadataTypeAttribute Classを付与することができます。(自動生成された Address クラスに手を加える必要はありません)

MetadataType 属性の引数に typeof(AddressMetaData) を設定することにより、メタデータクラス AddressMetaData を Address クラスに関連付けています。

以上の設定により、データアノテーション属性による検証が、クライアント側とサーバー側の両方で行われるようになります。

さらに、Display 属性も追加していますので、表示名が Display 属性の Name プロパティで設定した通りになります。

Tags: ,

Validation

ビューから Entity Data Model 生成

by WebSurfer 2011年4月24日 13:12

Visual Studio のデザイナを使って、テーブルではなくビューから Entity Data Model(以下、EDM と書きます)を作成する時の話です。

ビューから EDM を作成

ビューもしくは主キーを持たないテーブルから EDM を作成しようとすると、以下のようなエラーメッセージが出て、有効な EDM が生成されないことがあります。

「テーブル/ビュー 'xxxxx' に主キーが定義されておらず、有効な主キーを推論できませんでした。このテーブル/ビューは除外されました。エンティティを使用するには、スキーマを確認し、正しいキーを追加して、コメントを解除する必要があります。」

検索して調べてみると、そのあたりのことは The table/view does not have a primary key defined というページに詳しく書いてありました。要約すると、以下のとおりです。

EDM の各 Entity は Key を持つ必要があり、ビューや主キーのないテーブルの場合は、デザイナが NULL 不許可の列を主キーとして推定して EDM を生成します。

しかしながら、ビューが取得する全列が NULL 許可の場合、デザイナは主キーを推定できず、有効な EDM を生成できないので、上記のエラーメッセージが出るということだそうです。

その場合でも、関係する SSDL, CSDL, MSL は edmx ファイルの中に生成されていますが、SSDL 部分がコメントアウトされていたり、その他 CSDL, MSL も不完全な内容となってます。

以下の例は、すべての列が NULL 許可のビューから作成した EDM の中身です(xml ファイルなのでメモ帳で開くことができます)。

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="2.0" 
  xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
  <!-- EF Runtime content -->
  <edmx:Runtime>
    <!-- SSDL content -->
    <edmx:StorageModels>
      <Schema ・・・中略・・・

  <!--生成中に見つかったエラー:
  警告 6013: テーブル/ビュー 'xxxxx' に主キーが定義されてお
  らず、有効な主キーを推論できませんでした。このテーブル/ビ
  ューは除外されました。エンティティを使用するには、スキー
  マを確認し、正しいキーを追加して、コメントを解除する必要が
  あります。
      
  <EntityType Name="ViewForEdmTest">
    <Property Name="ContactName" Type="nvarchar" MaxLength="30" />
    <Property Name="ContactTitle" Type="nvarchar" MaxLength="30" />
    <Property Name="Address" Type="nvarchar" MaxLength="60" />
    <Property Name="City" Type="nvarchar" MaxLength="15" />
    <Property Name="Region" Type="nvarchar" MaxLength="15" />
    <Property Name="PostalCode" Type="nvarchar" MaxLength="10" />
    <Property Name="Country" Type="nvarchar" MaxLength="15" />
  </EntityType>-->

      </Schema>
    </edmx:StorageModels>

    <!-- CSDL content -->
    <edmx:ConceptualModels>
      ・・・中略・・・
    </edmx:ConceptualModels>

    <!-- C-S mapping content -->
    <edmx:Mappings>
      ・・・中略・・・
    </edmx:Mappings>
  </edmx:Runtime>

  <!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
  <Designer ・・・中略・・・
  </Designer>
</edmx:Edmx>

エラーメッセージの「正しいキーを追加して、コメントを解除・・・」というのは、それを書き直せということで、上に紹介したページの First Solution のことを言っています。

edmx ファイルをメモ帳で開いて、関係する SSDL, CSDL, MSL を書き直せば、確かに EDM 本体は有効になります。上の画像は、SSDL, CSDL, MSL を書き直したあと、edmx ファイルを Visual Studio で開いたもので、有効な EDM として表示されています(直す前は何も表示されません)。

ただし、Xxxxx.Designer.cs の定義が不完全なままなので、結局直した EDM はアプリケーションで利用できなかったのですが(自分が試した限りです)。

edmx ファイルを自力で書き直す以外の解決方法は以下の通りです。

  1. ビューが取得するフィールドに主キー列を含める。
  2. ISNULL 関数を利用する。

ビューにはもともと主キーなどはありませんが、ビューが取得するフィールドに主キー列が含まれていると、その列が NULL 不許可となり(デザイナがその列を主キーとして推定し)、EDM の生成に成功します。

2 番目の解決策は、上に紹介したページの Second Solution です。例えば、以下のように ID 列を追加してやります。なお、ROW_NUMBER() だけではダメで、ISNULL が必要ですので注意してください。

SELECT ISNULL((ROW_NUMBER() OVER (ORDER BY ContactName ASC)), 0) AS ID, ContactName, ContactTitle, Address, City, Region
FROM   dbo.Customers

なお、上記 1, 2 のいずれの場合も、EDM 生成時に以下のメッセージが出ますが、xxxxx.edmx ファイルは、xxxxx.Designer.cs を含めて、問題なく生成されているはずです。

「テーブル/ビュー 'xxxxx' には主キーが定義されていません。主キーは推論され、定義は読み取り専用のテーブル/ビューとして作成されました。」

Tags: , ,

ADO.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年5月  >>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar