为什么Validator.TryValidateObject以指数方式减速

时间:2014-09-28 23:04:45

标签: c# asp.net-mvc validation

我查询远程服务,一次接收一批100个产品,并继续这样做,直到不再有批次为止。我将这100个产品重新映射到我自己的产品对象,我希望验证并一次保存到数据库中。如果没有验证我记录错误并继续其余的。一旦前100个处理完毕,我就去下一批100个。总共大约有5000个。

我在浏览网站后看到的问题是 Validator.TryValidateObject 似乎需要更长时间才能运行。第一批1000分钟需要10分钟,第二批1000分钟需要20分钟,第三批1000分钟需要30分钟。所以每次看起来要花费10分钟。

Product类有一个伙伴类ProductValidation,其中包含用于验证的相应数据注释。我叫product.IsValid()。

    public class Product{
        public bool IsValid()
        {
            return this.IsValid<Product, ProductValidation>();
        }
    }

使用以下代码:

    public static bool IsValid<T, U>(this T obj)
    {
        if (typeof(T) != typeof(U))
        {
            TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(T), typeof(U)), typeof(T));
        }

        var validationContext = new ValidationContext(obj, null, null);
        var validationResults = new List<ValidationResult>();
        //The line below slows everything down. If commented out all is fine
        Validator.TryValidateObject(obj, validationContext, validationResults, true);

        if (validationResults.Count > 0)
            return false;
        else
            return true;
    }

为什么上述情景会以指数方式放缓?就像验证器每次都重新验证所有对象一样。

1 个答案:

答案 0 :(得分:2)

您描述的是二次运行时间,其中每单位工作成本随着完成的工作量线性增加。

我可以看到的最可能的解释是AddProviderTransparent扩展了一个具有线性搜索时间的列表,要么是因为它使用线性搜索,要么是因为哈希冲突和线性搜索通过桶。 / p>

如果为每个工作单元添加一个新提供程序,并为每个单元处理整个提供程序列表,那么您将获得二次运行时。

不是在每次调用时扩展提供者列表,而是仅在列表中尚未包含所需的提供者时才这样做。您可以使用HashSet<Pair<Type, Type>>来记住您已添加的T, U对。