【问题标题】:Custom validation unique property - generic classes自定义验证唯一属性 - 泛型类
【发布时间】:2020-11-19 10:12:14
【问题描述】:

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

这是我的代码,但这仅适用于指定的类,是否可以执行通过元数据获取正确类的方法?

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] 并且该方法采用带有注释的类并搜索相应的实体。

【问题讨论】:

标签: c# .net entity-framework validation data-annotations


【解决方案1】:

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

【讨论】:

  • 我正在尝试应用您的示例。关于你的最后一段我同意这一点,但在某些情况下,系统必须验证用户没有重复姓名。感谢您的提示!
  • @grteibo,不客气 :) 如果系统必须防止重复数据,最好在您的业务逻辑代码中执行此操作。在那里,您可以创建通用方法来检查重复条目并重用它。这种方法的语法可以是:bool IsUnique(string propertyName, object value, YourDbContext db)
  • 起初我接触了业务逻辑系统中的执行验证。但我认为最好通过实体中的注释来完成。
  • 好吧,我的表名和我的实体名不一样,所以现在我试图从一个实体中获取表名-.-
  • 只需将属性 (EntityName) 添加到属性并使用它而不是 className(如果它具有值),并在需要的地方设置如下属性:IsUnique(EntityName="EntityName")。但我没有编辑代码以保持更简单和全局作为答案。
【解决方案2】:

我认为最好的方法是让数据库发挥作用。

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

【讨论】:

    【解决方案3】:

    如果有通用属性就好了,但不支持。但是,您可以尝试使用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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-26
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多