エンティティフレームワークによって生成されたクラスにデータ注釈を追加する


93

エンティティフレームワークによって生成された次のクラスがあります。

public partial class ItemRequest
{
    public int RequestId { get; set; }
    //...

これを必須フィールドにしたい

[Required]
public int RequestId { get;set; }

ただし、これは生成されたコードであるため、これは消去されます。プロパティは生成された部分クラスによって定義されるため、部分クラスを作成する方法は想像できません。安全な方法で制約を定義するにはどうすればよいですか?


プロパティがintの場合、modelbinderにはデフォルトで必須であるため、[必須]属性は何も追加しません。
Kirill Bestemyanov 2013年

@KirillBestemyanov-@ Html.ValidationMessageFor(model => model.Item.Item.ResourceTypeID)はクライアント側で失敗するはずです。ありません。
P.Brian.Mackey 2013年

回答:


143

生成されたクラスItemRequestは常にpartialクラスです。これにより、必要なデータアノテーションが付けられた2番目の部分クラスを記述できます。あなたの場合、部分クラスItemRequestは次のようになります:

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

//make sure the namespace is equal to the other partial class ItemRequest
namespace MvcApplication1.Models 
{
    [MetadataType(typeof(ItemRequestMetaData))]
    public partial class ItemRequest
    {
    }

    public class ItemRequestMetaData
    {
        [Required]
        public int RequestId {get;set;}

        //...
    }
}

11
部分クラスは再生成されません。それが部分的として定義されている理由です。
MUG4N 2014

部分修飾子を見逃しましたか?同じ名前空間を使用していますか?
MUG4N、2015年

3
.NET Coreユーザー:MetadataTypeの代わりにModelMetadataTypeを使用します。
Bob Kaufman

1
名前空間が同一である限り、
任意の

40

以下のようMUG4Nは答えたあなたが使用できる部分クラスをより良い利用となりますインターフェイスを代わりに。この場合、EFモデルが検証モデルに対応していないと、コンパイルエラーが発生します。そのため、検証ルールが古くなることを恐れずにEFモデルを変更できます。

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace YourApplication.Models
{
    public interface IEntityMetadata
    {
        [Required]
        Int32 Id { get; set; }
    }

    [MetadataType(typeof(IEntityMetadata))]
    public partial class Entity : IEntityMetadata
    {
        /* Id property has already existed in the mapped class */
    }
}

PS ASP.NET MVCとは異なるプロジェクトタイプを使用している場合(手動でデータ検証を実行する場合)、バリデーターを登録することを忘れないでください

/* Global.asax or similar */

TypeDescriptor.AddProviderTransparent(
    new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Entity), typeof(IEntityMetadata)), typeof(Entity));

@dimonserの素晴らしい解決策、私はこのようなxmlコメントも追加してみました(コードで少し説明が必要なDBフィールドの場合-つまり、インテリタイプで表示するため)。それは機能していないようです。それを行う方法はありますか?
パーシー

こんにちは@Rick、インターフェースプロパティにコメントを付けることができますが、インターフェース変数を操作する場合にのみコメントが表示されます。または、部分クラスにコメントを入れることもできます。この場合、クラスのインスタンスを操作するときに表示されます。他のケースはありません。したがって、両方を使用してすべての状況をカバーできます。最初のケースではフィールド検証ルールを記述でき、2番目のケースでは目的を記述しようとします
デーモン

本当によく考えられた答えですが、検証が自動生成されたエンティティフレームワーククラスと同期しなくなった場合、コンパイルエラーを確認するのが私の好みです。エンティティフレームワーククラスに存在しないプロパティを検証する必要がある状況について考えるのに苦労しています。
Mike

1
これは私にはうまくいきません、それは私がIEntityMetadataインターフェースを実装する必要があると言います...
Worthy7

14

私はMUG4Nの答えのような解決策を見つけましたが、代わりにMetaDataエンティティクラス内にクラスをネストすることで、パブリック名前空間リスト内のクラスの数を減らし、各メタデータクラスに一意の名前を付ける必要をなくしました。

using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models 
{
    [MetadataType(typeof(MetaData))]
    public partial class ItemRequest
    {
        public class MetaData
        {
            [Required]
            public int RequestId;

            //...
        }
    }
}

私はプロジェクト全体でこれを使用しています。整理がはるかに簡単です。また、[NotMapped]必要に応じて、部分クラスの内部を使用してカスタムプロパティも追加します。
Carter Medlin 2016

5

これは、@ dimonser回答に対する一種の拡張です。dbモデルを再生成する場合、それらのクラスにインターフェースを手動で再追加する必要があります。

お腹が空いている場合は、.ttテンプレートを変更することもできます。

これは、いくつかのクラスでインターフェースを自動生成する例です。これは、あなたのメソッドを次のように.tt置き換えるだけのフラグメントEntityClassOpeningです(明らかvar stringsToMatchにエンティティ名とインターフェースを持ちます)。

public string EntityClassOpening(EntityType entity)
{
    var stringsToMatch = new Dictionary<string,string> { { "Answer", "IJourneyAnswer" }, { "Fee", "ILegalFee" } };
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}{4}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)),
        stringsToMatch.Any(o => _code.Escape(entity).Contains(o.Key)) ? " : " + stringsToMatch.Single(o => _code.Escape(entity).Contains(o.Key)).Value : string.Empty);
}

しかし、普通の人が自分でこれを行うべきではありません。これを行うために地獄に行くことが聖書で証明されています。


2

私はあなたが求めていることをどのように行うかわかりませんが、それを回避する方法があります。カスタムDataAnnotationsModelValidatorProviderのGetValidatorsをオーバーライドすることによる動的データ検証。その中で、(データベース、設定ファイルなどから)各フィールドを検証するためのルールを読み取り、必要に応じてバリデーターを追加できます。これには、検証がモデルと密接に結び付いていないという付加価値があり、サイトを再起動することなく変更できます。もちろんそれはあなたの場合にはやり過ぎかもしれませんが、私たちにとっては理想的でした!


この構造を最初に実装したときに行いました。その後、NHibernateに切り替えましたが、これはソリューションには関係ありません。検証コードは変更なしでそのまま機能しました(データアクセス層のみが変更されました)。
JTMon 2013年

1

必要な注釈を追加してT4テンプレートを変更します。このファイルは通常MODELNAME.ttという名前です

T4がクラスとメソッドを作成している場所を見つけて、これらをどこに配置するかを確認します。

     <#=codeStringGenerator.IgnoreJson(navigationProperty)#>


//create this method in file
public string IgnoreJson(NavigationProperty navigationProperty){
            string result = navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? "" : @"[JsonIgnore]
    [IgnoreDataMember]";

            return result;
        }

名前空間を追加する必要もあります。

<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using System.Runtime.Serialization;

モデルを保存してクラスを再構築します。すべてのメソッドに注釈を付ける必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.