2008-09-05 4 views
11

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

В частности, я хотел бы избежать код, подобный:

void Main() 
{ 
    ValidateTable1(); 
    ValidateTable2(); 
    ValidateTable3(); 
} 

private void ValidateTable1() 
{ 
    //Table1 validation code goes here 
} 

private void ValidateTable2() 
{ 
    //Table2 validation code goes here 
} 

private void ValidateTable3() 
{ 
    //Table3 validation code goes here 
} 

Кроме того, я решил использовать log4net войти все ошибки и предупреждения, так что каждый метод может быть объявлен void и Безразлично Не нужно ничего возвращать. Это хорошая идея или было бы лучше создать какой-то ValidationException, который ловит все исключения и сохраняет их в List<ValidationException>, прежде чем распечатывать их в конце?

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

На каком-то фоне программа будет записана либо на C#, либо на VB.NET, и таблицы, скорее всего, будут храниться в Access или SQL Server CE.

ответ

13

Просто обновленная информация по этому вопросу: Я решил пойти с Decorator pattern. То есть, у меня есть один «общий» класс таблицы, который реализует интерфейс IValidateableTable (который содержит метод validate()). Затем я создал несколько обработчиков проверки (которые также implement IValidateableTable), которые я могу обернуть вокруг каждой таблицы, которую я пытаюсь проверить.

Таким образом, код заканчивает тем, как это:

IValidateableTable table1 = new GenericTable(myDataSet); 
table1 = new NonNullNonEmptyColumnValidator(table1, "ColumnA"); 
table1 = new ColumnValueValidator(table1, "ColumnB", "ExpectedValue"); 

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

5

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

вы можете также выбрать, чтобы сделать некоторые магии, как это:

using(var validation = new ValidationScope()) 
{ 
    ValidateTable1(); 
    ValidateTable2(); 
    ValidateTable3(); 

    if(validation.Haserrors) 
    { 
     MessageBox.Show(validation.ValidationSummary); 
     return; 
    } 

    DoSomethingElse(); 
} 

тогда ValidateTable просто достичь в текущей области, например:

ValidationScope.Current.AddError("col1", "Col1 should not be NULL"); 

что-то по этому вопросу.

+0

Узоры дизайн очень хорошо, но часто простые решения, как этот более чем приемлемо для решения этой проблемы. – Samuel 2013-03-18 03:54:37

4

два подхода:

  1. CSLA где анонимные методы на бизнес-объекты используются для проверки.
  2. Прочитайте JP Boodhoo's блог, где он внедрил механизм правил и опубликовал очень подробные сообщения и образец кода. Вы также можете увидеть его на работе над эпизодом DNR Tv, который стоит посмотреть.
1

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

0

Я хотел бы попробовать с помощью комбинации моделей Factory и посетителей:

using System; 
using System.Collections.Generic; 

namespace Example2 
{ 
    interface IVisitor 
    { 
     void Visit(Table1 table1); 
     void Visit(Table2 table2); 
    } 

    interface IVisitable 
    { 
     void Accept(IVisitor visitor); 
    } 

    interface ILog 
    { 
     void Verbose(string message); 
     void Debug(string messsage); 
     void Info(string message); 
     void Error(string message); 
     void Fatal(string message); 
    } 

    class Error 
    { 
     public string Message { get; set; } 
    } 

    class Table1 : IVisitable 
    { 
     public int Id { get; set; } 
     public string Data { get; set; } 
     private IList<Table2> InnerElements { get; } = new List<Table2>(); 

     public void Accept(IVisitor visitor) 
     { 
      visitor.Visit(this); 

      foreach(var innerElement in InnerElements) 
       visitor.Visit(innerElement); 
     } 
    } 

    class Table2 : IVisitable 
    { 
     public int Id { get; set; } 
     public int Data { get; set; } 

     public void Accept(IVisitor visitor) 
     { 
      visitor.Visit(this); 
     } 
    } 

    class Validator : IVisitor 
    { 
     private readonly ILog log; 
     private readonly IRuleSet<Table1> table1Rules; 
     private readonly IRuleSet<Table2> table2Rules; 

     public Validator(ILog log, IRuleSet<Table1> table1Rules, IRuleSet<Table2> table2Rules) 
     { 
      this.log = log; 
      this.table1Rules = table1Rules; 
      this.table2Rules = table2Rules; 
     } 

     public void Visit(Table1 table1) 
     { 
      IEnumerable<Error> errors = table1Rules.EnforceOn(table1); 

      foreach (var error in errors) 
       log.Error(error.Message); 
     } 

     public void Visit(Table2 table2) 
     { 
      IEnumerable<Error> errors = table2Rules.EnforceOn(table2); 

      foreach (var error in errors) 
       log.Error(error.Message); 
     } 
    } 

    class RuleSets 
    { 
     private readonly IRuleSetFactory factory; 

     public RuleSets(IRuleSetFactory factory) 
     { 
      this.factory = factory; 
     } 

     public IRuleSet<Table1> RulesForTable1 => 
      factory.For<Table1>() 
       .AddRule(o => string.IsNullOrEmpty(o.Data), "Data1 is null or empty") 
       .AddRule(o => o.Data.Length < 10, "Data1 is too short") 
       .AddRule(o => o.Data.Length > 26, "Data1 is too long"); 

     public IRuleSet<Table2> RulesForTable2 => 
      factory.For<Table2>() 
       .AddRule(o => o.Data < 0, "Data2 is negative") 
       .AddRule(o => o.Data > 10, "Data2 is too big"); 
    } 

    interface IRuleSetFactory 
    { 
     IRuleSet<T> For<T>(); 
    } 

    interface IRuleSet<T> 
    { 
     IEnumerable<Error> EnforceOn(T obj); 
     IRuleSet<T> AddRule(Func<T, bool> rule, string description); 
    } 

    class Program 
    { 
     void Run() 
     { 
      var log = new ConsoleLogger(); 
      var factory = new SimpleRules(); 
      var rules = new RuleSets(factory); 
      var validator = new Validator(log, rules.RulesForTable1, rules.RulesForTable2); 

      var toValidate = new List<IVisitable>(); 
      toValidate.Add(new Table1()); 
      toValidate.Add(new Table2()); 

      foreach (var validatable in toValidate) 
       validatable.Accept(validator); 
     } 
    } 
} 
Смежные вопросы