自定义验证唯一 属性 - 通用 类
Custom validation unique property - generic classes
我正在尝试进行自定义验证 [IsUnique]。检查 属性 值是否是唯一的并且 return 是正确的消息。
这是我的代码,但这仅适用于指定的 class,是否可以执行一种通过元数据获取正确 class 的方法?
public class ArticleMetaData
{
[Required(AllowEmptyStrings = false)]
[IsUnique("Name")]
public String Name{ get; set; }
}
我的自定义验证:
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<String> properties;
List<string> propertiesList = new List<string>();
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],方法采用带注释的 class 并搜索相应的实体。
编写验证属性时,您可以使用 ValidationContext
获取有关验证的一些信息,例如您正在验证的 属性 的名称、您正在验证的对象类型等。
因此您不需要声明要检查哪个 属性 的唯一性,或者您应该检查哪个实体,或者不需要使用反射检索值的事件,因为该值具有已传递给 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<int>(
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<string>() { 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();
最好只使用可以离线验证的属性验证实体的这一方面。
StringLength、RegularExpression、Required 等验证属性是良好属性的示例,检查唯一性或其他数据库相关规则的验证属性是不适当属性的示例。
我认为最好的方法是让数据库发挥作用。
在数据库中创建一个约束以防止两篇文章具有相同的名称(或任何您需要的唯一性)。然后,当用户创建新文章或使用现有文章名称更新现有文章时,数据库将抛出异常。捕获该异常并让用户了解该问题。
如果有通用属性就好了,但是不支持。但是,您可以尝试使用 DbContext
的 Set
方法,该方法将实体类型作为参数。要查询非泛型 DbSet
,您可以使用 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);
}
}
我正在尝试进行自定义验证 [IsUnique]。检查 属性 值是否是唯一的并且 return 是正确的消息。
这是我的代码,但这仅适用于指定的 class,是否可以执行一种通过元数据获取正确 class 的方法?
public class ArticleMetaData
{
[Required(AllowEmptyStrings = false)]
[IsUnique("Name")]
public String Name{ get; set; }
}
我的自定义验证:
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<String> properties;
List<string> propertiesList = new List<string>();
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],方法采用带注释的 class 并搜索相应的实体。
编写验证属性时,您可以使用 ValidationContext
获取有关验证的一些信息,例如您正在验证的 属性 的名称、您正在验证的对象类型等。
因此您不需要声明要检查哪个 属性 的唯一性,或者您应该检查哪个实体,或者不需要使用反射检索值的事件,因为该值具有已传递给 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<int>(
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<string>() { 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();
最好只使用可以离线验证的属性验证实体的这一方面。
StringLength、RegularExpression、Required 等验证属性是良好属性的示例,检查唯一性或其他数据库相关规则的验证属性是不适当属性的示例。
我认为最好的方法是让数据库发挥作用。
在数据库中创建一个约束以防止两篇文章具有相同的名称(或任何您需要的唯一性)。然后,当用户创建新文章或使用现有文章名称更新现有文章时,数据库将抛出异常。捕获该异常并让用户了解该问题。
如果有通用属性就好了,但是不支持。但是,您可以尝试使用 DbContext
的 Set
方法,该方法将实体类型作为参数。要查询非泛型 DbSet
,您可以使用 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);
}
}