在验证项目的添加时调用DbContext.ValidateEntity,但是当我查询内部现有项目时,我可以看到该项目

时间:2022-06-24 02:16:41

I'm writing an ASP.NET MVC 4 web app. I'm using DbContext.ValidateEntity to check whether or not about-to-be-added entities pass some checks. Checks like whether or not their custom Name property is unique, or other properties pass my custom logic.

我正在编写一个ASP.NET MVC 4 Web应用程序。我正在使用DbContext.ValidateEntity检查有待添加的实体是否通过了一些检查。检查其自定义Name属性是否唯一,或其他属性是否通过我的自定义逻辑。

My unit tests have spotted some behavior that I didn't expect, though. I'm using the repository pattern and I have a global DbContext that I use and pass into my repository functions for retrieving EF model entities from the database.

我的单元测试发现了一些我没想到的行为。我正在使用存储库模式,我使用了一个全局DbContext,并将其传递到我的存储库函数中,以便从数据库中检索EF模型实体。

Up front, the problem is that inside of ValidateEntity, when looking at an entity that is being added, I query for all pre-existing entities and make sure that a particular field meets passes some uniqueness checks of mine. But, in the pre-existing items that I query, I already see the item being added.

在前面,问题是在ValidateEntity内部,当查看正在添加的实体时,我查询所有预先存在的实体并确保特定字段满足通过我的一些唯一性检查。但是,在我查询的预先存在的项目中,我已经看到了要添加的项目。

So for example, if no entities exist in the database and I am creating the first one, I will see it in ValidateEntity if I query for all existing entities.

因此,例如,如果数据库中没有实体并且我正在创建第一个实体,那么如果我查询所有现有实体,我将在ValidateEntity中看到它。

I thought that SaveChanges called ValidateEntity for all entities in the collection, prior to submitting them to the database?

在将它们提交到数据库之前,我认为SaveChanges为集合中的所有实体调用了ValidateEntity?

3 个解决方案

#1


1  

You shouldn't ever have to "check for uniqueness" in a database. The database is designed to do that for you already. Databases have something called Unique constraints that you can apply, and if your insert violates those constraints, an exception will be thrown. All you have to do is catch that exception and deal with it. Adding a bunch of code to do things the database does for you is redundant and slow, not to mention error prone as you're finding out.

您不应该在数据库中“检查唯一性”。数据库旨在为您完成此操作。数据库有一些称为可以应用的唯一约束,如果您的插入违反了这些约束,则会抛出异常。您所要做的就是捕获该异常并处理它。添加一堆代码来执行数据库为您执行的操作是多余且缓慢的,更不用说在您发现时容易出错。

#2


0  

Maybe you could use a custom validation attribute instead of using ValidateEntity? Here's an exemple of a custom attribute that check if the value is a decimal :

也许您可以使用自定义验证属性而不是使用ValidateEntity?这是一个自定义属性的示例,用于检查值是否为小数:

public class MustBeDecimalAttribute : ValidationAttribute, IClientValidatable
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (Equals(value, null))
                return ValidationResult.Success;

            using (new CultureSubstitution(CultureInfo.InvariantCulture))
            {
                if (string.IsNullOrWhiteSpace(value.ToString()))
                    return ValidationResult.Success;

                return !value.ToString().ToDecimal().HasValue
                           ? new ValidationResult(FormatErrorMessage(validationContext.DisplayName))
                           : ValidationResult.Success;
            }
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
                           {
                               ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
                               ValidationType = "mustbedecimal"
                           };

            yield return rule;
        }

But don't implement IClientValidatable since you need to query the db. When you have your attribute built, just add it to the Model like this :

但是不要实现IClientValidatable,因为您需要查询db。构建属性后,只需将其添加到模型中,如下所示:

[MustBeDecimal]
public decimal? RegularPrice { get; set; }

#3


0  

The problem ended up being with my DbContext. The DbContext should not be global because it's not at all thread safe. Thank you to Mystere Man for pointing that out.

问题最终出现在我的DbContext上。 DbContext不应该是全局的,因为它根本不是线程安全的。感谢Mystere Man指出这一点。

#1


1  

You shouldn't ever have to "check for uniqueness" in a database. The database is designed to do that for you already. Databases have something called Unique constraints that you can apply, and if your insert violates those constraints, an exception will be thrown. All you have to do is catch that exception and deal with it. Adding a bunch of code to do things the database does for you is redundant and slow, not to mention error prone as you're finding out.

您不应该在数据库中“检查唯一性”。数据库旨在为您完成此操作。数据库有一些称为可以应用的唯一约束,如果您的插入违反了这些约束,则会抛出异常。您所要做的就是捕获该异常并处理它。添加一堆代码来执行数据库为您执行的操作是多余且缓慢的,更不用说在您发现时容易出错。

#2


0  

Maybe you could use a custom validation attribute instead of using ValidateEntity? Here's an exemple of a custom attribute that check if the value is a decimal :

也许您可以使用自定义验证属性而不是使用ValidateEntity?这是一个自定义属性的示例,用于检查值是否为小数:

public class MustBeDecimalAttribute : ValidationAttribute, IClientValidatable
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (Equals(value, null))
                return ValidationResult.Success;

            using (new CultureSubstitution(CultureInfo.InvariantCulture))
            {
                if (string.IsNullOrWhiteSpace(value.ToString()))
                    return ValidationResult.Success;

                return !value.ToString().ToDecimal().HasValue
                           ? new ValidationResult(FormatErrorMessage(validationContext.DisplayName))
                           : ValidationResult.Success;
            }
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
                           {
                               ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
                               ValidationType = "mustbedecimal"
                           };

            yield return rule;
        }

But don't implement IClientValidatable since you need to query the db. When you have your attribute built, just add it to the Model like this :

但是不要实现IClientValidatable,因为您需要查询db。构建属性后,只需将其添加到模型中,如下所示:

[MustBeDecimal]
public decimal? RegularPrice { get; set; }

#3


0  

The problem ended up being with my DbContext. The DbContext should not be global because it's not at all thread safe. Thank you to Mystere Man for pointing that out.

问题最终出现在我的DbContext上。 DbContext不应该是全局的,因为它根本不是线程安全的。感谢Mystere Man指出这一点。