Синхронизация значений проверки между слоями - PullRequest
2 голосов
/ 16 февраля 2012

У меня есть вопрос относительно проверки данных между слоями.В качестве примера, скажем, у меня есть объект с именем Book со строковым свойством Title.

В БД у меня есть определенная длина для Title, которая будет определять, сколько символов я могу сохранить в своем свойстве Title.

Я проверяю запросы между каждым уровнем приложения.Поэтому я проверяю введенные пользователем данные на уровне представления, проверяю вызовы служб для моего уровня приложения, и база данных SQL, очевидно, проверяет данные, прежде чем я попытаюсь вставить их.

Мои вопросы, если у меня естьограничена длина до свойства Title, что является лучшим способом передачи этого через каждый уровень.Если в SQL Server указано, что длина не может превышать 40 символов, то это лучший способ сообщить об этом другим слоям без необходимости жесткого кодирования значения длины в каждом из них.

Что вы, ребята, делаете вэта ситуация?

Ответы [ 3 ]

2 голосов
/ 16 февраля 2012

Я не думаю, что есть готовое решение, которое будет делать именно то, что (то есть, привязывать проверку вашего домена к вашей БД)

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

Я бы порекомендовал использовать такие рамки, как FluentValidation

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

Итак, вам понадобится только один класс проверки для каждой модели, и, конечно, БД сообщит вам о любых проблемах на этом уровне.

В качестве альтернативы, если вам нужно, вы можете создать один класс проверки для каждого слоя, для каждого сценария или на самом деле так, как вы хотите.

Взгляните на код реализации из CodePlex ниже:

using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Company).NotNull();
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> 

failures = results.Errors;
2 голосов
/ 16 февраля 2012

Сначала:

база данных SQL, очевидно, проверит данные, прежде чем я попытаюсь вставить его

Нет, не будет. Если вы передаете его через параметр, он будет усечен. Если вы выполняете прямой SQL-оператор, вы получите ошибку после , когда вы запустите вставку.

Тем не менее, мы добавляем валидаторы к нашим объектам через атрибуты и позволяем проверке Enterprise Library перед попыткой передать данные на наш db-сервер. Это позволяет нам настраивать сообщение для каждого свойства и на нескольких языках.

Пример:

  using Microsoft.Practices.EnterpriseLibrary.Validation;
  using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

    namespace MyApp.ObjectModel {
      public class Account {
        private String _accountNumber = String.Empty;
        [StringLengthValidator(1, 50, MessageTemplateResourceName="ValidationStringLength", MessageTemplateResoourceType = typeof(MyApp.Properties.ErrorMessages), Tag="Account Number")]
        public String AccountNumber {
          get { return _accountNumber; }
          set { _accountNumber = value; }
        }


        protected Validator BuildValidator() {
          return ValidationFactory.CreateValidator<Account>();
        } // method::BuildValidator


        public String Validate() {
          Validator internalValidator = BuildValidator();
          ValidationResults info = internalValidator.Validate(this);
          String result = String.Empty;

          if (!info.IsValid) {
            foreach(ValidationResult vr in info) {
              result += vr.Message;
            }
          }
          return result;
        } // method::Validate


        public Boolean Save() {
          if (String.IsNullOrEmpty(Validate()) {
            // perform the save operation.
          } else {
            // do something else, log the message or send it back to the screen or whatever.
          }
        }
      } // class::Account
    }

Приведенный выше класс является очень простым примером использования валидаторов Enterprise Library. Основными вещами, которые нужно от этого избежать, является атрибут в свойстве AccountNumber, который в основном говорит, что номер счета должен содержать от 1 до 50 символов.

Мы поместили метод Validate () в базовый класс, который вызывается при каждом сохранении данных. Также наш метод validate фактически возвращает коллекцию ошибок, которые мы фильтруем для того, что пытается сохранить объект. Далее мы используем шаблон Inversion of Control для передачи соответствующего интерфейса уровня данных самому объекту. Таким образом, опять же, мы можем сохранить объекты, сохраняя логику внутри себя, при этом поддерживая возможности имитации, а также возможность по своему усмотрению менять механизмы сохранения (то есть: серверы баз данных). Это не представлено в примере кода выше.

По сути, это позволяет нам сохранять логику валидации в бизнес-классе, в то время как любой другой уровень может не знать об этом и просто фильтровать любые ошибки в соответствующем месте (обычно это область сообщений на экране). Если у вас есть специальная логика валидации, добавить обычные валидаторы и добавить атрибуты там, где они необходимы, довольно тривиально.

И последнее, что каждый уровень может вызывать метод validate () в любое время, а не только во время операции сохранения, для обеспечения согласованности данных.

0 голосов
/ 16 февраля 2012

Я предпочитаю иметь механизм, который позволяет мне проверять свои сущности перед попаданием в базу данных (в пользовательском интерфейсе и на бизнес-уровне)

Почему?

хорошо базы данных обычно не допускают каких-либо нарушений определенной схемы, и они обычно генерируют исключения, которые действительно плохи, особенно если вы работаете с постоянной средой, такой как NHibernate или Entity Framework (эти структуры обычно используют шаблон единицы работы и попробуйте сделать все вещи за один выстрел, и если что-то пойдет не так, нет никакой гарантии, что вы сможете сделать этот выстрел снова :))

Как?

В большинстве решений это означает метаданные (файлы конфигурации xml или атрибуты .net). и это означает синхронизацию этих метаданных с базой данных. MVC Framework имеет такой механизм из коробки, что, на мой взгляд, довольно круто Я никогда не видел альтернативы этому решению метаданных, но, возможно, мы сможем создать метаданные на лету, используя реальную схему базы данных.

Политика оповещения пользователя об этих нарушениях может быть различной. Некоторые предпочитают сразу же предупреждать пользователя о том, что что-то идет не так (проверка по полям), а некоторые предпочитают предупреждать пользователя после того, как он предоставил все данные (проверка по форме), но ясно одно: должна быть одна инфраструктура, ответственная за проверка модели в обоих случаях, и эта инфраструктура должна быть независимой от модели, поэтому ее можно использовать повторно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...