سؤال

إذا كان لدي مجموعة من جداول قاعدة البيانات (في ملف Access، على سبيل المثال) وأحتاج إلى التحقق من صحة كل جدول في هذه المجموعة مقابل مجموعة قواعد تحتوي على قواعد مشتركة عبر جميع الجداول بالإضافة إلى قواعد فردية خاصة بواحد أو مجموعة فرعية من الجداول، هل يمكن لأي شخص أن يوصي بنمط تصميم جيد للنظر فيه؟

على وجه التحديد، أود تجنب التعليمات البرمجية المشابهة لما يلي:

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> قبل طباعتها كلها في النهاية؟

لقد وجدت هذا, ، والذي يبدو أنه قد ينجح، لكنني آمل أن أجد بالفعل بعض نماذج التعليمات البرمجية للعمل عليها.أي اقتراحات؟هل قام أحد بشيء مماثل في الماضي؟

بالنسبة لبعض المعلومات الأساسية، سيتم كتابة البرنامج إما بلغة C# أو VB.NET ومن المرجح أن يتم تخزين الجداول في Access أو SQL Server CE.

هل كانت مفيدة؟

المحلول

مجرد تحديث على هذا:قررت أن أذهب مع نمط الديكور.وهذا يعني أن لدي فئة جدول "عامة" واحدة تقوم بتنفيذ IValidateableTable الواجهة (التي تحتوي على validate() طريقة).بعد ذلك، قمت بإنشاء العديد من أدوات تزيين التحقق من الصحة (والتي أيضًا implement IValidateableTable) والتي يمكنني الالتفاف حول كل جدول أحاول التحقق من صحته.

لذا، ينتهي الكود بالشكل التالي:

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

وبعد ذلك، كل ما علي فعله هو الاتصال table1.Validate() الذي ينحل من خلال الديكور الذي يستدعي جميع عمليات التحقق المطلوبة.حتى الآن، يبدو أن الأمر يعمل بشكل جيد حقًا، على الرغم من أنني لا أزال منفتحًا على الاقتراحات.

نصائح أخرى

سأعيد نوعًا من ملخص التحقق من الصحة لكل واحد ...أو قائمة 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");

شيء بهذا المعنى.

نهجان:

  1. CSLA حيث يتم استخدام الأساليب المجهولة على كائنات الأعمال للتحقق من الصحة.
  2. يقرأ جي بي بودهو مدونة حيث قام بتنفيذ محرك القواعد وتم نشر منشورات مفصلة للغاية ونموذج التعليمات البرمجية.يمكنك أيضًا رؤيته في العمل تلفزيون دي إن آر حلقة تستحق المشاهدة.

أعتقد أنك تتحدث حقًا عن مفهوم يسمى قيود في عالم قواعد البيانات.القيود هي الطريقة التي تضمن بها قاعدة البيانات سلامة البيانات التي تحتوي عليها.من المنطقي أكثر وضع هذا النوع من المنطق في قاعدة البيانات، بدلاً من التطبيق (حتى Access يقدم أشكالًا بدائية من القيود، مثل طلب تفرد القيم في عمود، أو قيم من قائمة، وما إلى ذلك).
يعد التحقق من صحة الإدخال (للحقول الفردية) أمرًا مختلفًا بالطبع، ويجب أن يستمر أي تطبيق في تنفيذ ذلك (لتقديم تعليقات لطيفة للمستخدم في حالة حدوث مشكلات)، حتى لو كانت قاعدة البيانات لديها قيود محددة جيدًا لأعمدة الجدول.

سأحاول استخدام مزيج من أنماط المصنع والزائر:

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);
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top