web-dev-qa-db-ja.com

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

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

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

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

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

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

91
P.Brian.Mackey

生成されたクラス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;}

        //...
    }
}
138
MUG4N

MUG4Nと答えたのでpartial classesを使用できますが、代わりにinterfacesを使用した方が良いでしょう。この場合、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 */
    }
}

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

/* Global.asax or similar */

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

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

using System.ComponentModel.DataAnnotations;

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

            //...
        }
    }
}
13
Carter Medlin

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

お腹が空いたら、.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);
}

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

5

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

2
JTMon

必要な注釈を追加して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;

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

1
tswales