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

时间:2009-08-10 10:05:40

标签: linq-to-sql validation

我刚开始使用LINQ to SQL类,并且非常喜欢这有助于我编写可读代码。 在文档中,典型的示例表明要进行自定义验证,您可以创建一个分部类::

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

同样适用于其他领域...... 然后在代码隐藏中,我输入这样的内容来显示错误消息并将用户保持在同一页面上以便纠正错误。

    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 个答案:

答案 0 :(得分:1)

这看起来像是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()方法将返回所有错误的集合,但不是调用Validate(),而是在准备好持久化时调用SubmitChanges()。 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 to SQL集成。如果要将VAB与LINQ to SQL一起使用,那么一定要阅读它。

答案 1 :(得分:0)

不是LINQ。大概你会在将它输入LINQ之前验证输入

您所看到的是具有例外情况的自然行为。

答案 2 :(得分:0)

我明白了。我没有在第一次失败的验证时抛出异常,而是在带有静态变量的类中存储错误消息。为此,我扩展了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,我会抛出异常。因此,不会尝试插入并保持用户在同一个输入页面上,而不会丢失他们输入的数据。