Добавить аннотации данных к классу, сгенерированному инфраструктурой сущности

У меня есть следующий класс, сгенерированный каркасом сущности:

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

Я хотел бы сделать это обязательным полем

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

Однако, поскольку это сгенерированный код, он будет уничтожен. Я не могу представить способ создания частичного класса, потому что свойство определяется порожденным частичным классом. Как я могу определить ограничение безопасным способом?

Ответ 1

Сгенерированный класс 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;}

        //...
    }
}

Ответ 2

В ответ на 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 */
    }
}

P.S. Если вы используете тип проекта, который отличается от ASP.NET MVC (при выполнении ручной проверки данных), не забудьте зарегистрировать валидаторы

/* Global.asax or similar */

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

Ответ 3

Я нашел решение вроде ответа MUG4N, но вместо этого вложил класс MetaData в класс сущности, тем самым уменьшив количество классов в вашем публичном списке имен и устранив необходимость иметь уникальное имя для каждого класса метаданных.

using System.ComponentModel.DataAnnotations;

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

            //...
        }
    }
}

Обязательно поместите "." в функции typeof.

Ответ 4

Это своего рода расширение для ответа @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);
}

Ни один нормальный человек не должен делать это сам с собой, хотя в Библии было доказано, что для этого идет ад.

Ответ 5

Я не уверен, как делать то, о чем вы просите, но есть способ обойти это. Динамическая проверка данных путем переопределения GetValidators вашего пользовательского DataAnnotationsModelValidatorProvider. В нем вы можете прочитать правила для проверки каждого поля (из базы данных, файла конфигурации и т.д.) И, при необходимости, добавить валидаторы. Он имеет добавленные значения, что ваша проверка более не тесно связана с моделью и может быть изменена без необходимости даже перезапуска сайта. Конечно, это может быть излишним для вашего дела, но это было идеально для наших!

Ответ 6

Измените шаблон 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;

Восстановите свои классы, сохранив свою модель, все ваши методы должны быть аннотированы.