엔티티 프레임 워크에서 생성 된 클래스에 데이터 주석 추가


93

엔터티 프레임 워크에서 생성 한 다음 클래스가 있습니다.

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

이 필드를 필수 필드로 만들고 싶습니다.

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

그러나 이것은 생성 된 코드이기 때문에 지워질 것입니다. 속성이 생성 된 부분 클래스에 의해 정의되기 때문에 부분 클래스를 만드는 방법을 상상할 수 없습니다. 안전한 방식으로 제약 조건을 어떻게 정의 할 수 있습니까?


속성이 int 인 경우 기본적으로 modelbinder에 필요하므로 [Required] 속성이 여기에 아무것도 추가하지 않습니다.
Kirill Bestemyanov 2013 년

@KirillBestemyanov-@ Html.ValidationMessageFor (model => model.Item.Item.ResourceTypeID)는 클라이언트 측에서 실패해야합니다. 그렇지 않습니다.
P.Brian.Mackey

답변:


143

생성 된 클래스 ItemRequest는 항상 partial클래스입니다. 이를 통해 필요한 데이터 주석으로 표시된 두 번째 부분 클래스를 작성할 수 있습니다. 귀하의 경우 부분 클래스 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

3
.NET Core 사용자 : MetadataType 대신 ModelMetadataType을 사용합니다.
Bob Kaufman

1
네임 스페이스가 동일하다면 원하는 곳에 partial 클래스를 넣을 수 있습니다
MUG4N

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 필드, 즉 intellitype으로 표시되어야 함) 작동하지 않는 것 같습니다. 어떻게하는지 아십니까?
Percy

@Rick 님, 인터페이스 속성에 주석을 달 수는 있지만 인터페이스 변수로 작업 할 때만 볼 수 있습니다. 또는 부분 클래스에 주석을 넣을 수 있습니다. 이 경우 클래스의 인스턴스로 작업 할 때 볼 수 있습니다. 사용 가능한 다른 케이스가 없습니다. 따라서 두 가지를 모두 사용하여 모든 상황을 처리 할 수 ​​있습니다. 첫 번째 경우에는 필드 유효성 검사 규칙을 설명하고 두 번째 경우에는 목적을 설명 할 수 있습니다
dimonser

정말 잘 생각한 답변이지만 유효성 검사가 더 이상 자동 생성 된 엔티티 프레임 워크 클래스와 동기화되지 않으면 컴파일 오류를 보는 것이 좋습니다. 엔티티 프레임 워크 클래스에 더 이상 존재하지 않는 속성의 유효성을 검사하려는 상황을 생각하는 데 어려움을 겪고 있습니다.
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

5

이것은 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);
}

정상적인 사람은 스스로 이것을해서는 안되며,이를 위해 지옥에 간다는 것이 성경에서 입증되었습니다.


2

나는 당신이 요구하는 것을 어떻게하는지 잘 모르겠지만 그에 대한 방법이 있습니다. 사용자 지정 DataAnnotationsModelValidatorProvider의 GetValidators를 재정 의하여 동적 데이터 유효성 검사. 여기에서 (데이터베이스, 구성 파일 등에서) 각 필드의 유효성을 검사하는 규칙을 읽고 필요에 따라 유효성 검사기를 추가 할 수 있습니다. 유효성 검사가 더 이상 모델과 밀접하게 결합되지 않고 사이트를 다시 시작하지 않고도 변경할 수 있다는 부가 가치가 있습니다. 물론 귀하의 경우에는 과잉 일 수 있지만 우리에게는 이상적이었습니다!


우리는이 구조를 처음 구현했을 때했습니다. 이후 NHibernate로 전환했지만 이는 솔루션과 관련이 없습니다. 유효성 검사 코드는 변경없이 그대로 작동했습니다 (데이터 액세스 레이어 만 변경됨).
JTMon

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.