自定义验证唯一属性-泛型类

本文关键字:泛型类 属性 唯一 验证 自定义 | 更新日期: 2023-09-27 18:09:17

我试图使一个自定义验证[IsUnique]。检查属性值是否唯一,并返回正确的消息。

这是我的代码,但这只适用于指定的类,是否可以通过元数据做一个方法来获得适当的类?

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]和方法获取带有注释的类并搜索相应的实体

自定义验证唯一属性-泛型类

在编写验证属性时,您可以使用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、regulareexpression、Required等都是好的属性,而检查唯一性或其他数据库相关规则的验证属性则是不合适的属性。

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

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

如果有泛型属性就好了,但是不支持。但是,您可以尝试使用以实体类型作为参数的DbContextSet方法。要查询非通用的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);
    }
}