none
DataAnnotations - copy paste code, он так задуман? RRS feed

  • Вопрос

  • Здравствуйте!
    у меня есть проблема c  DataAnnotations в ASP MVC.
    Я когда начинал  изучать ASP MVC мне показалось как крут  DataAnnotations и  декларативен :)

    Я попробовал DataAnnotations на реальном проекте и испытал боль!
    Приведу пример допустим - на сайте два типа аккаунта
    1)юридическое лицо
    2)физическое лицо

    public class RegistrationOFindividual
        {
            [Required]
            [Display(Name = "Логин")]
            [StringLength(20,MinimumLength = 5)]
            [RegularExpression(@"^[a-z0-9]{1}[a-z0-9_.-]{1,15}$/")]
            public string Login    { get; set; }
    
            [Required]
            [Display(Name = "Пароль")]
            [StringLength(15, MinimumLength = 4)]
            [RegularExpression(@"^.*(?=.{8,40})(?=.*\d)(?=.*[a-zA-Z])(?=.*[@\-_,./\:+*]).*$")]
            public string Password { get; set; }
            //properties with metadata
        }
    
        public class RegistrationOfOrg
        {
            [Required]
            [Display(Name = "Логин")]
            [StringLength(20, MinimumLength = 5)]
            [RegularExpression(@"^[a-z0-9]{1}[a-z0-9_.-]{1,15}$/")]
            public string Login { get; set; }
    
            [Required]
            [Display(Name = "Пароль")]
            [StringLength(15, MinimumLength = 4)]
            [RegularExpression(@"^.*(?=.{8,40})(?=.*\d)(?=.*[a-zA-Z])(?=.*[@\-_,./\:+*]).*$")]
            public string Password { get; set; }
    
            //properties with metadata
        }

    Еще добавим модель которая меняет пароль.

    public class PasswordChange
        {
            [Required]
            [Display(Name = "Пароль")]
            [StringLength(15, MinimumLength = 4)]
            [RegularExpression(@"^.*(?=.{8,40})(?=.*\d)(?=.*[a-zA-Z])(?=.*[@\-_,./\:+*]).*$")]
            public string Password { get; set; }
    
            //properties with metadata
        }

    И что мы видел copy paste  - 2 раза описывается логин  и 3 раза почти пароль!

    Очень не хватает функции что бы можно один раз описать metadata для“логин” а потом пользоваться весь де  в рамках проекта!

    мне интересно это специально Microsoft сделали так что бы программисты нарушали заповедь не copy paste :)

    Я не понимаю  почему компания microsoft смогла сделать например очень удобную разметку razor , а сделать удобною надстройку на  DataAnnotations не смогла !?

    Можно использовать DataAnnotations   и избавится от copy paste ?

    6 октября 2012 г. 17:54

Ответы

  • Не в обиду конечно, но что Вы прицепились к этому наследованию. Прописывайте атрибут валидации только в классе сущности, в остальных местах не надо. И к тому же поле пароль это всего лишь поле класса сущности и делать для него отдельный класс бесмысленно, он входит в сущность как поле и из себя в отдельности ничего не представляет.  И не нужно создавать десять таких  классов. Используйте объект вашей сущности в классе ViewModel и проблема сама отпадёт. У Вас пока что проблема в моделировании, а как построите правильную модель, всё встанет на свои места.
    • Предложено в качестве ответа YatajgaEditor 10 октября 2012 г. 5:41
    • Помечено в качестве ответа Abolmasov DmitryModerator 10 октября 2012 г. 7:16
    8 октября 2012 г. 15:09
    Модератор
  • "Прописывайте атрибут валидации только в классе сущности, в остальных местах не надо." согласен полностью, я бы сам с радостью прописал правила только в сущностях  .я могу спроектировать сущности    и заполнить  их metadata.

    если я не ошибаюсь я все понял , у меня была проблема с viewmodel, я почему то думал  что все свойства   которые находится в  viewmodel должны быть использованы   все сразу.

    я понял если  я не ошибаюсь.

    1)в viewmode вложить сущности которые нам понадобится.

    2)затем в view отобразить все свойства  которые нам нужны

    3)при сохранение в контроллере , нужно вытащить все нужные  сущности из субд, обновить их свойства которые мы хотим по тем данным которые пришли из view

    4)обновленные сущности проверить на валидация , если все хорошо сохранить изменение в базе данных

     да теперь нет проблемы.

    Я все правильно понял?

    • Предложено в качестве ответа YatajgaEditor 10 октября 2012 г. 5:41
    • Помечено в качестве ответа Abolmasov DmitryModerator 10 октября 2012 г. 7:16
    8 октября 2012 г. 17:43

Все ответы

  • По правде говоря у Вас сама модель не верно организована. Делайте один класс, с общими полями, плюс добавачное поле, например типа bool, описывающее тип аккаунта.
    6 октября 2012 г. 18:52
    Модератор
  • Да и ещё: функционал -"менять пароль" не должен входить в саму модель, т.е. не являться сущностью. Это функции репозитория (хранилища), которая может быть реализована служебным классом.
    6 октября 2012 г. 18:55
    Модератор
  • Я специально сделал простой пример. описанный пример это выдуманный пример.

    я понимаю что  нужно вынести в отдельный  class - login и пароль, а уже от  юридического лица  и физического лица наследовать  от общего  класса с общими свойствами. Но наследование не всегда поможет.



    6 октября 2012 г. 19:26
  • Да и ещё: функционал -"менять пароль" не должен входить в саму модель, т.е. не являться сущностью. Это функции репозитория (хранилища), которая может быть реализована служебным классом.
    Можно подробней что вы имеете виду под "Это функции репозитория (хранилища), которая может быть реализована служебным классом." я не понял вас , но может это именно тот функционал которого мне не хватает. 
    6 октября 2012 г. 19:51
  • Я это и говорю, проблема в самой организации. Проблема в том что пример надуман, не будет этого, проблема сама исчезнет. "я понимаю что  нужно вынести в отдельный  class - login и пароль, а уже от  юридического лица  и физического лица наследовать  от общего  класса с общими свойствами. Но наследование не всегда поможет." - в данном случае наследование не нужно. Всё это атрибуты одной сущности, они должны инкапсулироваться в один класс. Не может же быть чтобы у одного человека было два пароля или два логина на одну учётную запись. "Можно подробней что вы имеете виду" - да, вот пожалуйста.
    6 октября 2012 г. 19:57
    Модератор
  • public class BaseMetadatas { [DisplayName("Price")] [Required] [RegularExpression(@"^\$?\d+(\.(\d{2}))?$")] public decimal UnitPrice { get; set; }

     //properties with metadata

    } public class Product { [CopyMetadataFromProperty(typeof(BaseMetadatas), "UnitPrice")] public decimal UnitPrice;

     	//properties with metadata

    }

    можно реализовать вроде  такой функции CopyMetadataFromProperty?
    6 октября 2012 г. 20:19
  • Я это и говорю, проблема в самой организации. Проблема в том что пример надуман, не будет этого, проблема сама исчезнет. "я понимаю что  нужно вынести в отдельный  class - login и пароль, а уже от  юридического лица  и физического лица наследовать  от общего  класса с общими свойствами. Но наследование не всегда поможет." - в данном случае наследование не нужно. Всё это атрибуты одной сущности, они должны инкапсулироваться в один класс. Не может же быть чтобы у одного человека было два пароля или два логина на одну учётную запись. "Можно подробней что вы имеете виду" - да, вот пожалуйста.
    Ссылка битая.
    6 октября 2012 г. 20:25
  • Можно и так, если атрибуты не наследуются.
    7 октября 2012 г. 6:12
    Модератор
  • interface IAmALazyUser
    {
        [Required]
        string FirstName {get; set; }
        [Required]
        string LastName {get; set; }
    }
    
    class User : IAmALazyUser
    {
        public string FirstName {get; set; }
        public string LastName {get; set; }
        public DateTime RegistrationDate {get; }
    }
    
    class CreateUserViewModel : IAmALazyUser
    {
        public string FirstName {get; set; }
        public string LastName {get; set; }    
    }
    я думаю если можно было через interface прописать это было бы лучше чем   MetadataType он ограничен! 

    7 октября 2012 г. 13:30
  • В интерфейсе не нужно указывать атрибуты, и нужно указывать в классе, ведь в конечном счёте он реализует функциональность. Интерфейс это просто-напросто контракт, который должен реализовать Ваш класс.
    7 октября 2012 г. 17:24
    Модератор
  • Да и ещё: функционал -"менять пароль" не должен входить в саму модель, т.е. не являться сущностью. Это функции репозитория (хранилища), которая может быть реализована служебным классом.

    вы хотите сказать что для функции "менять пароль" не нужно использовать viewmodel? да я  согласен это не сущность но есть большое НО как мы тогда сделаем валидацию     для нового пароля, не забывайте у пароля есть максимальное и минимальное возможное значение и регулярное выражение.

    7 октября 2012 г. 18:25
  • "вы хотите сказать что для функции "менять пароль" не нужно использовать viewmodel?" - нужно, ещё как. Просто надо атрибуты проверки прописывать в конечную реализацию, чем является класс, а не интерфейс.
    8 октября 2012 г. 6:13
    Модератор
  • "вы хотите сказать что для функции "менять пароль" не нужно использовать viewmodel?" - нужно, ещё как. Просто надо атрибуты проверки прописывать в конечную реализацию, чем является класс, а не интерфейс.

    Я хорошо знаю что нужно в класс прописывать атрибуты,  "я думаю если можно было через interface прописать это было бы лучше чем   MetadataType он ограничен!" - а это написал потому что intefece поддерживает множественное наследие  а MetadataType можно указать только 1 класс.

    пока ничего лучше не придумал ,как не дублировать metadata для пароля.

    public class InputBase<T>
        {
            public virtual T Data { get; set; }
        }
    
        public class InputPasswordBase : InputBase<string>
        {
            [Required]
            [StringLength(15, MinimumLength = 4)]
            [RegularExpression(@"^.*(?=.*\d)(?=.*[a-zA-Z])(?=.*[@\-_,./\:+*]).*$")]
            [DataType(DataType.Password)]
            public override string Data { get; set; }
        }
    
    
    
        public class InputNewPasswordForChange : InputPasswordBase
        {
            [DisplayName("Новый пароль")]
            public override string Data { get; set; }
        }
    
        public class InputPasswordForRegister : InputPasswordBase
        {
            [DisplayName("Введите пароль")]
            public override string Data { get; set; }
        }
    
    
        public class ChangePasswordViewModel
        {
            [DisplayName("Введите текущий пароль")]
            public string OldPassword { get; set; }
    
            public InputNewPasswordForChange NewPassword { get; set; }
            //properties with metadata
        }
    
        public class RegisterBaseViewModel
       {
    
            public InputPasswordForRegister Password { get; set; }
           //properties with metadata
       }







    8 октября 2012 г. 13:02
  • Не в обиду конечно, но что Вы прицепились к этому наследованию. Прописывайте атрибут валидации только в классе сущности, в остальных местах не надо. И к тому же поле пароль это всего лишь поле класса сущности и делать для него отдельный класс бесмысленно, он входит в сущность как поле и из себя в отдельности ничего не представляет.  И не нужно создавать десять таких  классов. Используйте объект вашей сущности в классе ViewModel и проблема сама отпадёт. У Вас пока что проблема в моделировании, а как построите правильную модель, всё встанет на свои места.
    • Предложено в качестве ответа YatajgaEditor 10 октября 2012 г. 5:41
    • Помечено в качестве ответа Abolmasov DmitryModerator 10 октября 2012 г. 7:16
    8 октября 2012 г. 15:09
    Модератор
  • "Прописывайте атрибут валидации только в классе сущности, в остальных местах не надо." согласен полностью, я бы сам с радостью прописал правила только в сущностях  .я могу спроектировать сущности    и заполнить  их metadata.

    если я не ошибаюсь я все понял , у меня была проблема с viewmodel, я почему то думал  что все свойства   которые находится в  viewmodel должны быть использованы   все сразу.

    я понял если  я не ошибаюсь.

    1)в viewmode вложить сущности которые нам понадобится.

    2)затем в view отобразить все свойства  которые нам нужны

    3)при сохранение в контроллере , нужно вытащить все нужные  сущности из субд, обновить их свойства которые мы хотим по тем данным которые пришли из view

    4)обновленные сущности проверить на валидация , если все хорошо сохранить изменение в базе данных

     да теперь нет проблемы.

    Я все правильно понял?

    • Предложено в качестве ответа YatajgaEditor 10 октября 2012 г. 5:41
    • Помечено в качестве ответа Abolmasov DmitryModerator 10 октября 2012 г. 7:16
    8 октября 2012 г. 17:43
  • Именно так оно и есть, всё верно.
    8 октября 2012 г. 17:58
    Модератор