有没有更好的方法来处理LINQ to SQL验证?

问题描述:

除了抛出异常之外,还有什么方法可以解决使用LINQ to SQL中的部分验证方法取消插入记录的方法吗?有没有更好的方法来处理LINQ to SQL验证?

+0

如果我理解了这个问题,我想你可以使用TransactionScope:http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx并提交或处理更改。 – Jacob 2010-03-07 10:56:22

我可以理解,你不想在一个属性设置为无效值后直接抛出异常。这种方法使得向用户正确传达实际错误的难度。但是,我认为最好避免使用这些部分验证方法。国际海事组织你想抛出一个异常,当你的模型是无效的,但只是在你坚持你的模型到数据库。

我建议您使用验证框架并将其与您的LINQ to SQL DataContext类集成。这里有一个如何与Enterprise Library Validation Application Block做到这一点的例子,但这个概念会为你选择的每一个验证框架的工作:

public partial class NorthwindDataContext 
{ 
    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 ValidationResult[] Validate() 
    { 
     // here we use the Validation Application Block. 
     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();    
    } 

    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; 
    } 
} 

有如DataAnnotations和 的Enterprise Library Validation Application Block(VAB)提供了一些验证框架。 VAB非常适合这样做。使用LINQ to SQL,您的实体会生成,因此您需要使用VAB提供的基于配置的方法(不要尝试使用属性装饰您的实体)。通过重写SubmitChanges方法,您可以确保在实体持久化之前触发验证。我的答案是herehere包含有关使用VAB的有用信息。

我写了一些关于将VAB与LINQ to SQL herehere集成在一起的有趣文章。 LINQ to SQL(与Entity Framework 1.0相比)的好处是生成了很多有用的元数据。将此与VAB结合使用时,您可以使用此元数据来验证模型,而无需手动连接每个验证。可以从模型中提取最大字符串长度和非空值的特别验证。阅读here如何做到这一点。

VAB来拯救!

+0

我会看看那些文章。谢谢 – 2010-03-08 11:42:01

+0

@Sir Psycho:我已经更新了我的答案。这有希望更好地回答你的问题。 – Steven 2010-03-08 13:28:31

+0

您是否认为您的任何建议都过时了? – Merritt 2012-03-06 23:08:17

最终这表明你在的最后一道防线(在任何数据库限制之前,至少)你的数据是无效的。如果你想做一些除了大声尖叫之外的事情,那么可以在之前验证数据(通过多种方法中的任何一种),将其添加到插入列表中。

作为一个额外的想法,你可能尝试覆盖SubmitChanges(在数据上下文);获取变更集,验证插入和删除(删除 - 提交,哪个IIRC检查插入列表并删除它们)任何你已经决定的错误。然后致电base.SubmitChanges。但对我而言,这有点倒退。

为了说明,这只做了一个插入(不是按要求填写两个),但我不喜欢这种方法。完全一样。只要我们清楚; -p

namespace ConsoleApplication1 { 
    partial class DataClasses1DataContext { // extends the generated data-context 
     public override void SubmitChanges(
       System.Data.Linq.ConflictMode failureMode) { 
      var delta = GetChangeSet(); 
      foreach (var item in delta.Inserts.OfType<IEntityCheck>()) { 
       if (!item.IsValid()) { 
        GetTable(item.GetType()).DeleteOnSubmit(item); 
       } 
      } 
      base.SubmitChanges(failureMode); 
     } 
    } 
    public interface IEntityCheck { // our custom basic validation interface 
     bool IsValid(); 
    } 
    partial class SomeTable : IEntityCheck { // extends the generated entity 
     public bool IsValid() { return this.Val.StartsWith("d"); } 
    } 
    static class Program { 
     static void Main() { 
      using (var ctx = new DataClasses1DataContext()) { 
       ctx.Log = Console.Out; // report what it does 
       ctx.SomeTables.InsertOnSubmit(new SomeTable { Val = "abc" }); 
       ctx.SomeTables.InsertOnSubmit(new SomeTable { Val = "def" }); 
       ctx.SubmitChanges(); 
      } 
     } 
    } 
} 
+0

我从来没有说过我想要执行两个插入:)我喜欢这种方法。我会放弃这一点,让你知道我是如何去的。谢谢:) – 2010-03-08 11:45:18

+0

@Marc Gravell:虽然它回答了他的问题,但我认为在保存之前静静地删除无效实体有点可怕。我知道Phycho询问不使用异常,但IMO最好用异常消息抛出异常。 – Steven 2010-03-08 13:33:01

+0

Steven,这不是关于沉默,而是关于在例外情况下使用例外。验证不是一个意想不到的事情,因此不需要抛出异常...... IMO :-) – 2010-03-09 10:35:24