如何设置自定义验证的位置.state == EntityState.Added

本文关键字:位置 state 验证 EntityState Added 自定义 何设置 设置 | 更新日期: 2023-09-27 18:03:37

如何设置自定义验证,当Entry.state == EntityState.Added为真时,下面的代码将工作!自定义验证码:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class UniqueEmailAddress : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        this.email = (string)value;
        using (G9EntityDataBaseClass oEntity = new G9EntityDataBaseClass())
        {
            if (oEntity.User.Where(u => u.email == email).Count() == 0)
            {
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult(ErrorMessageString);
            }
        }
    }
}

使用:

[CustomValidation.UniqueEmailAddress]
public string email { set; get; }

i need ((NOT)EntityState.Added):

if (Entry.state != EntityState.Added){
     return ValidationResult.Success;
}

我应该把Entry.state从哪里带来

如何设置自定义验证的位置.state == EntityState.Added

一个很好的验证方法是在你的实体类中实现IValidatableObject:

public class User: IValidatableObject

Validate方法中,您可以通过将实体对象添加到ValidationContext来访问当时附加的上下文。因此,您的验证可能看起来像:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var context = (G9EntityDataBaseClass)validationContext.Items["Context"];
    if (context.User
               .Where(u => u.email == email && u.UserID != this.UserID)
               .Any())
    {
        return new ValidationResult(ErrorMessageString);
    }
    else
    {
        return ValidationResult.Success;
    }
}

您可以通过在DbContext类中重写此方法将上下文添加到验证上下文:

protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,
                       IDictionary<object, object> items)
{
    items.Add("Context", this);
    return base.ValidateEntity(entityEntry, items);
}

逻辑很简单:如果有一个相同的email属于另一个用户(u.UserID != this.UserID),则验证总是失败。这既适用于插入新用户(ID = 0),也适用于插入现有用户。

顺便说一下,您是否应该在这里实际使用上下文来访问数据库是有争议的,但是替代的,重写DbContext.ValidateEntity也不吸引我,因为这会导致长链的代码充满类型强制转换,每次只需要一个。对于验证的每个实体,将遍历此代码。Validate方法id只在合适的时候执行。

您需要获取实体所附加的上下文以查看其状态。ValidationContext可以用来在验证属性类中获取额外的信息,它在创建时接受iserviceprovider的实现,大多数IoC容器要么实现了这个实现,要么有包装器。

所以,如果你运行在一个环境与IoC容器,可以控制你的属性类的创建(例如,通过注册一个DataAnnotationsModelValidator在MVC中),并有规则创建你的上下文(例如,每HTTP请求),你可能能够访问当前上下文的属性,并使用它来查看实体的状态被验证

如果不了解更多的上下文,这段代码运行在什么框架中,你想要实现什么行为,很难说这是否是一个可行的方法。

@Gert Arnold post是一种方法,如果你想使用属性,你可以通过ObjectInstance属性从ValidationContext中找到对象

var user = validationContext.ObjectInstance as User;
if(user==null) return new ValidationResult("...");
using(var db=new SomeDbContext()){
    var has=db.User.Any(x=>x.Id!=user.Id && x.email==value);
    if (has) return new ValidationResult("...");
    else return ValidationResult.Success;
}

当添加时,id为0,所以在db中,没有id为0的记录,所以如果有1条记录有相同的电子邮件,any()返回true。
更新时,您有一个id,因此x.id!=user。