C#自定义validation唯一属性 – generics类

我正在尝试进行自定义validation[IsUnique]。 检查属性值是否唯一并返回正确的消息。

这是我的代码,但这只适用于指定的类,是否可以通过元数据来获取正确的类?

public class ArticleMetaData { [Required(AllowEmptyStrings = false)] [IsUnique("Name")] public String Name{ get; set; } } 

我的自定义validation:

 class IsUnique : ValidationAttribute { public IsUnique(string propertyNames) { this.PropertyNames = propertyNames; } public string PropertyNames { get; private set; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var myproperty = validationContext.ObjectType.GetProperty(PropertyNames); var value = propiedad.GetValue(validationContext.ObjectInstance, null); IEnumerable properties; List propertiesList = new List(); propertiesList.Add(myproperty.Name); var dba = new myContext(); if (dba.Articles.Any(article => article.Name == (string)value)) { return new ValidationResult("The name already exist", propertiesList); } return null; } } 

我们的想法是只使用注释[isUnique],方法将带有注释的类并搜索相应的实体。

编写validation属性时,可以使用ValidationContext获取有关validation的一些信息,例如要validation的属性名称,要validation的对象类型等。

因此,您不需要声明要检查哪个属性的唯一性,或者应该检查哪个实体,或者不需要使用reflection检索值的事件,因为该值已传递给IsValid方法。

使用DbContext时,您可以执行Sql查询,因此您可以使用sql查询简单地检查唯一性。 它比尝试动态创建通用linq查询更简单。

可能这个想法对你有帮助。 根据这个想法,您的代码中有一些更改:

 protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var db = new YourDBContext(); var className = validationContext.ObjectType.Name.Split('.').Last(); var propertyName = validationContext.MemberName; var parameterName = string.Format("@{0}", propertyName); var result = db.Database.SqlQuery( string.Format("SELECT COUNT(*) FROM {0} WHERE {1}={2}", className, propertyName, parameterName), new System.Data.SqlClient.SqlParameter(parameterName, value)); if (result.ToList()[0] > 0) { return new ValidationResult(string.Format("The '{0}' already exist", propertyName), new List() { propertyName }); } return null; } 

要使用此属性,只需将[IsUnique]放在属性上方即可。

 [IsUnique] YourProperty { get; set; } 

然后使用这样的代码运行测试:

 var db = new YourDbContext(); db.Configuration.ValidateOnSaveEnabled = true; db.Categories.Add(new YourEntity() { YourProperty = "DuplicateName" }); db.SaveChanges(); 

使用可以离线validation的属性仅validation实体的此类方面是一种很好的做法。

validation属性如StringLength,RegularExpression,Required和此类validation是良好属性的示例,检查uniqness或其他数据库相关规则的validation属性是不适当属性的示例。

我认为最好的方法是让数据库完成它的工作。

在数据库中创建约束以防止两篇文章具有相同的名称(或您需要的任何唯一性)。 然后,当用户创建新文章或使用现有文章名称更新现有文章时,数据库将引发exception。 捕获该exception并让用户知道该问题。

如果有通用属性会很好,但不支持这些属性。 但是,您可以尝试使用DbContextSet方法,该方法将实体类型作为参数。 要查询非genericsDbSet ,可以使用System.Linq.Dynamic库(可以从NuGet添加它)。 它允许使用字符串谓词查询DbSet 。 这是一个例子:

 var existingEntityQuery = myContext.Set(validationContext.ObjectType) .Where("Name= @0", (string)value); var enumerator = existingEntityQuery.GetEnumerator(); if (enumerator.MoveNext()) { var entity = enumerator.Current; if (entity != null) { return new ValidationResult("The name already exist", propertiesList); } }