代码之家  ›  专栏  ›  技术社区  ›  naim5am

Linq to SQL验证所有字段,而不仅仅是在第一个失败字段处停止

  •  1
  • naim5am  · 技术社区  · 15 年前

    我刚开始使用linq-to-sql类,非常喜欢它如何帮助我编写可读的代码。 在文档中,典型的示例说明要进行自定义验证,可以创建一个分部类,如下所示:

    partial class Customer 
    {
        partial void OnCustomerIDChanging(string value)
        {
            if (value=="BADVALUE") throw new NotImplementedException("CustomerID Invalid");
        }
    }
    

    其他领域也是如此… 然后在codebehind中,我放置类似这样的东西来显示错误消息,并让用户保持在同一页上,以便纠正错误。

        public void CustomerListView_OnItemInserted(object sender, ListViewInsertedEventArgs e)
    {
        string errorString = "";
        if (e.Exception != null)
        {
          e.KeepInInsertMode = true;
          errorString += e.Exception.Message;
          e.ExceptionHandled = true;
        }
        else errorString += "Successfully inserted Customer Data" + "\n";
        errorMessage.Text = errorString;
    }
    

    好吧,这很容易,但是一旦抛出第一个异常,它就会停止验证其余字段!!如果用户犯了一个以上的错误,她/他/它只会收到第一个错误的通知。 是否有其他方法检查所有输入并显示每个输入中的错误? 谢谢你的建议。

    3 回复  |  直到 10 年前
        1
  •  1
  •   Steven    10 年前

    这看起来像是 Enterprise Library Validation Application Block (VAB)。VAB设计用于返回所有错误。除此之外,它不会引发异常,因此您可以简单地要求它为您验证类型。

    当您决定使用VAB时,我建议您-不要-使用linq to sql的onxxxchanging和onvalidate方法。最好重写DataContext类上的SubmitChange(ConflictMode)方法以调用VAB的验证API。这将使验证逻辑远离业务实体,从而保持实体的干净。

    请看以下示例:

    public partial class NorthwindDataContext
    {
        public ValidationResult[] Validate()
        {
            return invalidResults = (
                from entity in this.GetChangedEntities()
                let type = entity.GetType()
                let validator = ValidationFactory.CreateValidator(type)
                let results = validator.Validate(entity)
                where !results.IsValid
                from result in results
                select result).ToArray();            
        }
    
        public override void SubmitChanges(ConflictMode failureMode)
        {
            ValidationResult[] this.Validate();
    
            if (invalidResults.Length > 0)
            {
                // You should define this exception type
                throw new ValidationException(invalidResults);
            }
    
            base.SubmitChanges(failureMode);
        }
    
        private IEnumerable<object> GetChangedEntities()
        {
            ChangeSet changes = this.GetChangeSet();
    
            return changes.Inserts.Concat(changes.Updates);
        }
    }
    
    [Serializable]
    public class ValidationException : Exception
    {
        public ValidationException(IEnumerable<ValidationResult> results)
            : base("There are validation errors.")
        {
            this.Results = new ReadOnlyCollection<ValidationResult>(
                results.ToArray());
        }
    
        public ReadOnlyCollection<ValidationResult> Results
        {
            get; private set; 
        }
    }
    

    调用validate()方法将返回所有错误的集合,但当您准备好持久化时,我只调用SubmitChanges(),而不调用validate()。submitChanges()现在将检查错误,并在其中一个实体无效时引发异常。因为错误列表被发送到validationException,所以您可以在调用堆栈上方的错误上迭代,并将它们呈现给用户,如下所示:

    try
    {
        db.SubmitChanges();
    }
    catch (ValidationException vex)
    {
        ShowErrors(vex.ValidationErrors);
    }
    
    private static void ShowErrors(IEnumerable<ValidationResult> errors)
    {
        foreach(var error in errors)
        {
            Console.WriteLine("{0}: {1}", error.Key, error.message);
        }
    }
    

    使用此方法时,请确保在将实体保存到数据库之前始终对其进行验证。

    Here 这是一篇很好的文章,解释了如何将VAB与LINQ集成到SQL中。如果您想使用VAB和LINQ to SQL,就一定要阅读它。

        2
  •  0
  •   Lasse V. Karlsen    15 年前

    不是LINQ。假设您将验证输入 之前 把它交给林肯。

    你所看到的是自然行为,除了例外。

        3
  •  0
  •   naim5am    15 年前

    我知道了。我将错误消息存储在带有静态变量的类中,而不是在验证失败时引发异常。为此,我对DataContext类进行如下扩展:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for SalesClassesDataContext
    /// </summary>
    public partial class SalesClassesDataContext
    {
        public class ErrorBox
        {
            private static List<string> Messages = new List<string>();
            public void addMessage(string message)
            {
                Messages.Add(message);
            }
            public List<string> getMessages() 
            {
                return Messages;
            }
        }
    }
    

    在每个表对应的类中,我将继承新定义的类,如下所示:

    public partial class Customer : SalesClassesDataContext.ErrorBox
    

    只有在onvalidate函数中,如果错误数不是0,我才会抛出异常。因此,在不丢失用户输入的数据的情况下,不会尝试插入并保持用户在同一输入页上。