Додайте примітки до даних до класу, згенерованого структурою сутності


93

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

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

Я хотів би зробити це обов'язковим полем

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

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


Якщо ваше властивість int, воно за замовчуванням потрібне для modelbinder, тому ваш атрибут [Required] не додасть сюди нічого.
Кирило Бестем’янов

@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

ви пропустили частковий модифікатор? Чи використовуєте ви той самий простір імен?
MUG4N

3
Користувачі .NET Core: використовуйте ModelMetadataType замість MetadataType.
Боб Кауфман,

1
Ви можете розмістити частковий клас куди завгодно, якщо простір імен однаковий
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), але це, здається, не працює. Будь-яка ідея, як це зробити?
Персі

Привіт @Rick, ви можете додати коментар до властивості інтерфейсу, але ви побачите це лише тоді, коли будете працювати зі змінною інтерфейсу. Або ви можете додати коментар до часткового класу. У цьому випадку ви побачите це, коли будете працювати з екземпляром свого класу. Інших випадків немає. Тож ви можете використовувати обидва з них для охоплення всіх ситуацій. У першому випадку ви можете описати правила перевірки поля, а у другому випадку спробувати описати цілі
dimonser

Дійсно добре продумана відповідь, але моїм перевагою було б бачити помилки компіляції, якщо перевірка більше не синхронізується з автогенерованим рамковим класом сутності. Я намагаюся подумати про ситуацію, коли ви можете перевірити властивість, яка більше не присутня у вашому класі фреймворку.
Майк

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]всередині часткового класу теж, коли вони мені потрібні.
Картер Медлін

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

Я не впевнений, як робити те, що ви просите, але є спосіб його вирішити. Динамічна перевірка даних шляхом заміни GetValidators вашого користувацького DataAnnotationsModelValidatorProvider. У ньому ви можете прочитати правила перевірки кожного поля (з бази даних, конфігураційного файлу тощо) та додати валідатори за потребою. Він додав значення, що ваша перевірка більше не пов’язана з моделлю і може бути змінена без необхідності навіть перезапускати сайт. Звичайно, це може бути непосильним для вашого випадку, але це було ідеально для нашого!


Ми це зробили, коли вперше реалізували цю структуру. З тих пір ми перейшли до NHibernate, але це не стосується рішення. Наш код перевірки працював так само, як без змін (змінено лише рівень доступу до даних).
JTMon

1

Змініть шаблон T4, додавши необхідні анотації, цей файл зазвичай називається MODELNAME.tt

знайти, де Т4 створює клас і методи, щоб знати, куди їх поставити.

     <#=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;

Відновіть свої класи, зберігаючи вашу модель, всі ваші методи повинні бути анотовані.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.