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

是否有更好的方法来处理LINQ to SQL中的验证?

  •  2
  • Razor  · 技术社区  · 15 年前

    除了抛出异常之外,还有什么方法可以使用Linq to SQL中的部分验证方法来取消记录的插入?

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

    我可以理解,您不希望在属性设置为无效值后直接引发异常。这种方法使得很难正确地与用户沟通到底出了什么问题。但是,我认为最好不要使用那些部分验证方法。IMO您希望在模型无效时抛出一个异常,但仅在将模型持久化到数据库之前抛出。

    我建议您使用一个验证框架,并将它与您的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; 
        }
    }
    

    有几种可用的验证框架,如数据注释和 这个 企业库验证应用程序块 (VAB)。VAB非常适合这样做。使用Linq to SQL,您的实体将被生成,因此您需要使用VAB提供的基于配置的方法(不要尝试用属性来装饰您的实体)。通过重写SubmitChanges方法,可以确保在实体被持久化之前触发验证。我的答案 here here 包含有关使用VAB的有用信息。

    我写了一些关于将vab与linq集成到SQL的有趣文章 here here . LinqtoSQL(与EntityFramework1.0相比)的好处在于生成了大量有用的元数据。当将其与VAB结合使用时,您可以使用此元数据来验证模型,而无需手动连接每个验证。尤其是,可以从模型中提取最大字符串长度(而非空)的验证。读 here 如何做到这一点。

    救出吸血鬼!

        2
  •  1
  •   Marc Gravell    15 年前

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

    作为一个额外的想法,你 能够 尝试推翻 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();
                }
            }
        }
    }