C#将DataAnnotations添加到EntityFramework中的实体

我正在使用ADO.Netentity framework。 为了处理输入validation,我正在尝试使用DataAnnotations ,我查看了StavkOverflow和Google,并且我发现几乎所有使用MetadataType示例。 但是,我已经尝试了几个小时而且我无法使它工作..出于某种原因, EmployeeMetaData类中的CustomAttributes没有应用于EmployeeMetaData类上的相应字段/属性。 有谁知道为什么会发生这种情况? 是的,我确信属性类型和名称完全匹配。

感谢任何帮助,我已经坚持了几个小时。 提前致谢。

EntityExtentions.cs

 [MetadataType(typeof(EmployeeMetaData))] public partial class Employee:IDataErrorInfo { public string Error { get { return String.Empty; } } public string this[string property] { get { return EntityHelper.ValidateProperty(this, property); } } } public class EmployeeMetaData { [Required(AllowEmptyStrings=false, ErrorMessage = "A name must be defined for the employee.")] [StringLength(50, ErrorMessage = "The name must be less than 50 characters long.")] public string Name { get; set; } [Required(ErrorMessage = "A username must be defined for the employee.")] [StringLength(20, MinimumLength = 3, ErrorMessage = "The username must be between 3-20 characters long.")] public string Username { get; set; } [Required(ErrorMessage = "A password must be defined for the employee.")] [StringLength(20, MinimumLength = 3, ErrorMessage = "The password must be between 3-20 characters long.")] public string Password { get; set; } } 

EntityHelper.cs

 public static class EntityHelper { public static string ValidateProperty(object obj, string propertyName) { PropertyInfo property = obj.GetType().GetProperty(propertyName); object value = property.GetValue(obj, null); List errors = (from v in property.GetCustomAttributes(true).OfType() where !v.IsValid(value) select v.ErrorMessage).ToList(); // I was trying to locate the source of the error // when I print out the number of CustomAttributes on the property it only shows // two, both of which were defined by the EF Model generator, and not the ones // I defined in the EmployeeMetaData class // (obj as Employee).Username = String.Join(", ", property.GetCustomAttributes(true)); return (errors.Count > 0) ? String.Join("\r\n", errors) : null; } } 

我使用了这个(URL指向有用的文章,我提出了一些想法):

 // http://www.clariusconsulting.net/blogs/kzu/archive/2010/04/15/234739.aspx ///  /// Validator provides helper methods to execute Data annotations validations ///  public static class DataValidator { ///  /// Checks if whole entity is valid ///  /// Validated entity. /// Returns true if entity is valid. public static bool IsValid(object entity) { AssociateMetadataType(entity); var context = new ValidationContext(entity, null, null); return Validator.TryValidateObject(entity, context, null, true); } ///  /// Validate whole entity ///  /// Validated entity. /// The entity is not valid. public static void Validate(object entity) { AssociateMetadataType(entity); var context = new ValidationContext(entity, null, null); Validator.ValidateObject(entity, context, true); } ///  /// Validate single property of the entity. ///  /// Type of entity which contains validated property. /// Type of validated property. /// Entity which contains validated property. /// Selector for property being validated. /// The value of the property is not valid. public static void ValidateProperty(TEntity entity, Expression> selector) where TEntity : class { if (selector.Body.NodeType != ExpressionType.MemberAccess) { throw new InvalidOperationException("Only member access selector is allowed in property validation"); } AssociateMetadataType(entity); TProperty value = selector.Compile().Invoke(entity); string memberName = ((selector.Body as MemberExpression).Member as PropertyInfo).Name; var context = new ValidationContext(entity, null, null); context.MemberName = memberName; Validator.ValidateProperty(value, context); } ///  /// Validate single property of the entity. ///  /// Type of entity which contains validated property. /// Entity which contains validated property. /// Name of the property being validated. /// The entity does not contain property with provided name. /// The value of the property is not valid. public static void ValidateProperty(TEntity entity, string memberName) where TEntity : class { Type entityType = entity.GetType(); PropertyInfo property = entityType.GetProperty(memberName); if (property == null) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Entity does not contain property with the name {0}", memberName)); } AssociateMetadataType(entity); var value = property.GetValue(entity, null); var context = new ValidationContext(entity, null, null); context.MemberName = memberName; Validator.ValidateProperty(value, context); } // http://buildstarted.com/2010/09/16/metadatatypeattribute-with-dataannotations-and-unit-testing/ // Data Annotations defined by MetadataTypeAttribute are not included automatically. These definitions have to be injected. private static void AssociateMetadataType(object entity) { var entityType = entity.GetType(); foreach(var attribute in entityType.GetCustomAttributes(typeof(MetadataTypeAttribute), true).Cast()) { TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(entityType, attribute.MetadataClassType), entityType); } } } 

该validation器的最大缺点是:

  • 它像蜗牛一样表现。 如果您在单个实体上执行它并不重要,但如果您想要使用数百,数千或更多实体,则无关紧要。
  • 它不支持开箱即用的复杂类型 – 您必须创建特殊属性并在元数据中使用它来validation复杂类型
  • 我上次使用DataAnnotations进行任何业务validation。 它们仅用于少量实体的UIvalidation。

validation复杂类型/嵌套对象的属性:

 ///  /// Attribute for validation of nested complex type. ///  [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class ValidateComplexTypeAttribute : ValidationAttribute { public override bool IsValid(object value) { return DataValidator.IsValid(value); } } 

尝试validation:

 using System.ComponentModel.DataAnnotations; Validator.TryValidateProperty(propertyValue, new ValidationContext(this, null, null) { MemberName = propertyName }, validationResults); 

我有同样的问题,并在http://blogs.msdn.com/b/davidebb/archive/2009/07/24/using-an-associated-metadata-class-outside-dynamic-data.aspx找到我的解决方案

关键是调用静态函数TypeDescriptor.AddProvider()

 using System.ComponentModel.DataAnnotations; TypeDescriptor.AddProvider( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(YourEntityClass)), typeof(YourEntityClass)); 

由于CustomAttributes未应用于Employee类的属性,因此提出了此解决方法。 所以我只是在实体上获得了MetaDataType类,找到了相应的属性并通过ValidationAttributes运行了该值。

 public static class EntityHelper { public static string ValidateProperty(object obj, string propertyName) { // get the MetadataType attribute on the object class Type metadatatype = obj.GetType().GetCustomAttributes(true).OfType().First().MetadataClassType; // get the corresponding property on the MetaDataType class PropertyInfo property = metadatatype.GetProperty(propertyName); // get the value of the property on the object object value = obj.GetType().GetProperty(propertyName).GetValue(obj, null); // run the value through the ValidationAttributes on the corresponding property List errors = (from v in property.GetCustomAttributes(true).OfType() where !v.IsValid(value) select v.ErrorMessage).ToList(); // return all the errors, or return null if there are none return (errors.Count > 0) ? String.Join("\r\n", errors) : null; } } [MetadataType(typeof(Employee.MetaData))] public partial class Employee:IDataErrorInfo { private sealed class MetaData { [Required(AllowEmptyStrings = false, ErrorMessage = "A name must be defined for the employee.")] [StringLength(50, MinimumLength = 3, ErrorMessage = "The name must be between 3-50 characters long.")] public object Name { get; set; } [Required(AllowEmptyStrings = false, ErrorMessage = "A username must be defined for the employee.")] [StringLength(20, MinimumLength = 3, ErrorMessage = "The username must be between 3-20 characters long.")] public object Username { get; set; } [Required(AllowEmptyStrings = false, ErrorMessage = "A password must be defined for the employee.")] [StringLength(20, MinimumLength = 3, ErrorMessage = "The password must be between 3-20 characters long.")] public object Password { get; set; } } public string Error { get { return String.Empty; } } public string this[string property] { get { return EntityHelper.ValidateProperty(this, property); } } }