如何在Entry.state == EntityState.Added的位置设置自定义validation

如何设置自定义validation,当Entry.state == EntityState.Added为true时,以下代码将起作用! 自定义validation码:

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

我需要((NOT)EntityState.Added):

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

我应该从哪里带Entry.state

适用于validation的方法是在实体类中实现IValidatableObject :

 public class User: IValidatableObject 

Validate方法中,您可以通过将实体对象添加到ValidationContext来访问实体对象所附加到的上下文。 所以您的validation可能如下所示:

 public IEnumerable 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类中重写此方法,可以将上下文添加到validation上下文中:

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

逻辑很简单:如果有一个属于另一个用户的相同emailu.UserID != this.UserID ),validation总是会失败。 这适用于插入新用户(ID = 0)和现有用户。

顺便说一下,你是否应该在这里实际使用上下文来访问数据库是有争议的,但另一方面,重写DbContext.ValidateEntity也不会吸引我,因为这会导致代码长度很长的代码只有一个每次都是必要的。 并且为经过validation的每个实体遍历此代码。 Validate方法id仅在适用时执行。

您需要获取实体所附加的上下文以查看其状态。 ValidationContext可用于获取validation属性类的额外信息,它在创建时采用IServiceProvdier的实现,大多数IoC容器实现或具有包装器。

因此,如果您在具有IoC容器的环境中运行并且可以控制属性类的创建(例如,通过在MVC中注册DataAnnotationsModelValidator)并具有用于创建上下文的规则(例如,根据HTTP请求),您可以访问属性中的当前上下文,并使用它来查看正在validation的实体的状态。

虽然这并没有理解更多的上下文,但是这个代码运行的框架以及你试图实现它的行为很难说这是否是一个可行的方法。

@Gert Arnold的post是一种方式,如果你想使用use属性,你可以通过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.id可以除了这个记录自己。