web-dev-qa-db-ja.com

Entity Frameworkデータモデルを使用した検証属性の追加

序文2015年2月引き続きEntity Framework EDMXを使用している場合は、代わりにEntity Framework Code Firstを使用して、ぜひご自身でチェックアウトしてください。違いは、テーブルがモデルクラスを作成するEDMXではなく、モデルクラスからテーブルが作成されることです。それは万能の簡単な解決策であり、この質問の問題は存在しません!

最初にMVC 5を使用してEntity Framework 6コードを開始する

既存のSQLデータベースがあり、モデルにADO.NET Enity Data Modelを使用しています。私はいくつかのCRUD機能をMVCアプリケーションに組み込んでいます。

私がこのテーマで見つけたすべてのチュートリアルでは、モデルを最初から構築し、属性をモデルクラスに追加します。例えば:

    [Required]
    [StringLength(10)]
    public string Name { get; set; }

ただし、モデルクラスは自動生成されるため、変更することはお勧めできません(データベースモデルを更新すると上書きされます)。

検証属性を追加するにはどうすればよいですか?

24
Mason240

EF生成クラスとは別に、メタデータを格納する部分クラスを作成できます。

//Contact.cs - The original auto-generated file 
[System.ComponentModel.DataAnnotations.MetadataType(typeof(ContactMetadata))]
public partial class Contact
{
    public int ContactID { get; set; }
    public string ContactName { get; set; }
    public string ContactCell { get; set; }
}

//ContactMetadata.cs - New, seperate class

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
internal sealed class ContactMetadata
{
    [Required(ErrorMessage = "Name is required.")]
    [StringLength(5)]  
    public string ContactName;
}
36
Mason240

Mason240の回答はうまくいきます。私はそれを改善しようとします。次のコマンドで新しいContactDataAnnotations.csクラスを作成できます。

//ContactDataAnnotations.cs - A new file 
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

[MetadataType(typeof(ContactMetadata))]
public partial class Contact
{
    // No field here
}

internal sealed class ContactMetadata
{
    [Required(ErrorMessage = "Name is required.")]
    [StringLength(5)]  
    public string ContactName {get; set; }
}

このようにして、DataAnnotationsに触れずに、そして警告なしに、EFを介してContactクラスを再生成できます。

18

これに回答済みのマークが付いていることはわかっていますが、いくつかの点を整理します。

@SteveCavは言った:「このメンバーは複数回定義されている」。私は同じまったく同じエラーがありました。理解するために費やした時間。

最後にそれを修正するには、同じアセンブリ内に別のファイルクラスを作成する必要があります(これについては既にここで説明しています)。ただし、強調したいのは、このクラスは内部クラスを表す部分クラスでネストする必要があるということです。

次に、その内部クラスをAnnotationクラスで装飾します。このような:

//ContactMap.cs - Present in the same namespace as Contact.cs
[System.ComponentModel.DataAnnotations.MetadataType(typeof(ContactMap))]
partial class Contact // Present in the ContactMap class. This represent the Inner Class
{
}

//ContactMap.cs - This represent the outer class

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public class ContactMetadata
{
    [Required(ErrorMessage = "Name is required.")]
    [StringLength(5)]  
    public string ContactName;
}

これがより明確で理解しやすいものであることを願っています。

4
Francky

これはすでに正しく回答されていますが、メタデータをネストすることは、私にとっては少しすっきりした印象のIMHOだと私はいつも思っていることも付け加えておきます。

[MetadataType(typeof(ProductDescription.Metadata))]
public partial class ProductDescription
{
    sealed class Metadata
    {
        [Key]
        public long id { get; set; }
        [Display(Name = "Title")]
        public string title { get; set; }
        // ...
    }
}

また、メタデータをクラスに対してプライベートに保つことの追加の利点にも気付きました。属性は正しいクラスでのみ機能し、クラスを複製(類似のクラスを作成するため)した場合に発生する可能性のあるバグを防ぎます。複製されたクラスの名前を変更するときに属性のクラス名を変更し忘れると、バグが発生する可能性があります。

4
James Wilkins

ここでは、さまざまなアセンブリと名前空間でクラスを使用できるようにする提案された回答のバリエーションがあります。実際にはEFでテストしていませんが、これをSwagger codegen APIモデルクラスに使用しています。

簡単に言うと、モデルクラスから継承し、継承したクラスにメタデータを追加します。追加の利点は、Swagger codegenを使用すると、マッピングなしでAPIモデルを直接使用でき、初期フォームでは保護されたデフォルトのctorを使用できることです。

[MetadataType(typeof(LocalAssemblyModelMetadata))]
public class LocalAssemblyModel : IO.Swagger.Model.OtherAssemblyModel 
{
    public LocalAssemblyModel() : base ()     { }
}



public sealed class LocalAssemblyModelMetadata
{
    [Required(ErrorMessage = "BaseclassProperty is mandatory.")]
    public string BaseclassProperty { get; set; }
}
3
Sentinel