C#从添加的EntityFramework到DataAnnotations实体 [英] C# adding DataAnnotations to entities from the EntityFramework

查看:1356
本文介绍了C#从添加的EntityFramework到DataAnnotations实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的ADO.Net Entity Framework的。为了处理输入验证我试图使用 DataAnnotations ,我看了看周围的StavkOverflow和谷歌,到处都有我发现,几乎用同样的例子 MetadataType 。不过,我一直在尝试了几个小时,我无法得到它的工作..出于某种原因,从CustomAttributes的 EmployeeMetaData 类没有被应用到各个领域/在员工类属性。没有人有任何想法,为什么这可能发生?是的,我敢肯定,属性类型和名称完全匹配。



任何帮助表示赞赏,我一直停留在这几个小时。
先谢谢了。



EntityExtentions.cs



  [MetadataType(typeof运算(EmployeeMetaData))] 
公共部分类员工:IDataErrorInfo的
{
公共字符串错误{{返回的String.Empty; }}
公共字符串此[字符串属性]
{
得到
{
返回EntityHelper.ValidateProperty(这一点,属性);
}
}
}

公共类EmployeeMetaData
{
[必需(AllowEmptyStrings =假的ErrorMessage =的名称必须定义,为员工)]
[StringLength(50的ErrorMessage =该名称必须少于50个字符长)]
公共字符串名称{。组; }

[必需(的ErrorMessage =A用户名必须为员工定义。)]
[StringLength(20,MinimumLength = 3的ErrorMessage =该用户名必须是3间。长20个字符)]
公共字符串用户名{获得;组; }

[必需(的ErrorMessage =密码必须为员工定义。)]
[StringLength(20,MinimumLength = 3的ErrorMessage =密码必须是3间。长20个字符)]
公共字符串密码{搞定;组; }
}



EntityHelper.cs



 公共静态类EntityHelper 
{
公共静态字符串ValidateProperty(obj对象,字符串propertyName的)
{
的PropertyInfo财产= obj.GetType()的getProperty(propertyName的);
对象值= property.GetValue(OBJ,NULL);
名单,LT;字符串>误差=(从property.GetCustomAttributes V(真).OfType< ValidationAttribute>()其中v.IsValid(值)选择v.ErrorMessage!).ToList();

//我试图查找错误
源//当我打印出来的财产CustomAttributes数那只能说明
//二,两者的这是由EF模型发生器限定,而不是那些
//我在EmployeeMetaData类
//(物镜作为雇员).Username =的string.join(定义,,property.GetCustomAttributes (真正));

回报率(errors.Count大于0)?的string.join(\r\\\
,错误):空;
}
}


解决方案

我用这一个(网址指向有用的文章,我花了一些想法):

  // HTTP://www.clariusconsulting。净/博客/ kzu /存档/ 2010/04/15 / 234739.aspx 
///<总结>
///验证提供帮助方法来执行数据注解验证
///< /总结>
公共静态类DataValidator
{
///<总结>
///检查是否整个实体是有效的
///< /总结>
///< PARAM NAME =实体>验证实体LT; /参数>
///<退货和GT;如果实体是有效的,则返回true< /回报>
公共静态布尔的IsValid(对象实体)
{
AssociateMetadataType(实体);

VAR背景=新ValidationContext(实体,NULL,NULL);
返回Validator.TryValidateObject(实体,背景,空,真);
}

///<总结>
///验证整个实体
///< /总结>
///< PARAM NAME =实体>验证实体LT; /参数>
///&下;异常CREF =ValidationException>该实体无效&下; /异常>
公共静态void验证(对象实体)
{
AssociateMetadataType(实体);

VAR背景=新ValidationContext(实体,NULL,NULL);
Validator.ValidateObject(实体的背景下,真正的);
}

///<总结>
///验证实体的一个属性。
///< /总结>
///< typeparam NAME =TEntity方式>实体类型的含有有效的财产和LT; / typeparam>
///< typeparam NAME =TProperty>验证属性的类型< / typeparam>
///< PARAM NAME =实体>实体,其中包含验证属性< /参数>
///< PARAM NAME =选择>选择物业正在验证< /参数>
///<异常CREF =ValidationException>该属性的值无效< /异常>
公共静态无效ValidateProperty< TEntity,TProperty>(TEntity实体,表达式来; Func键< TEntity,TProperty>>选择器),其中TEntity:类
{
如果(selector.Body.NodeType! = ExpressionType.MemberAccess)
{
抛出新的InvalidOperationException异常(只有成员访问选择是允许在属性验证);
}

AssociateMetadataType(实体);

TProperty值= selector.Compile()调用(实体)。
串memberName =((selector.Body为MemberExpression)。成员为的PropertyInfo).Name点;

VAR背景=新ValidationContext(实体,NULL,NULL);
context.MemberName = memberName;
Validator.ValidateProperty(值,背景);
}

///<总结>
///验证实体的一个属性。
///< /总结>
///< typeparam NAME =TEntity方式>实体类型的含有有效的财产和LT; / typeparam>
///< PARAM NAME =实体>实体,其中包含验证属性< /参数>
///< PARAM NAME =memberName>该属性的名称被验证< /参数>
///<异常CREF =InvalidOperationException异常方式> /异常>不包含财产提供者的名称和LT的实体;
///<异常CREF =ValidationException>该属性的值无效< /异常>
公共静态无效ValidateProperty< TEntity>(TEntity实体,串memberName)其中TEntity:类
{
类型的EntityType = entity.GetType();
的PropertyInfo财产= entityType.GetProperty(memberName);

如果(财产== NULL)
{
抛出新的InvalidOperationException异常(的String.Format(CultureInfo.InvariantCulture,
实体不包含名为{属性0},memberName));
}

AssociateMetadataType(实体);

VAR值= property.GetValue(实体,NULL);

VAR背景=新ValidationContext(实体,NULL,NULL);
context.MemberName = memberName;
Validator.ValidateProperty(值,背景);
}

// http://buildstarted.com/2010/09/16/metadatatypeattribute-with-dataannotations-and-unit-testing/ $ B $定义b //数据注释通过MetadataTypeAttribute不会自动包括在内。这些定义必须注射。
私有静态无效AssociateMetadataType(对象实体)
{
变种的EntityType = entity.GetType();

的foreach(在entityType.GetCustomAttributes(var属性typeof运算(MetadataTypeAttribute),真).Cast< MetadataTypeAttribute>())
{
TypeDescriptor.AddProviderTransparent(
新AssociatedMetadataTypeTypeDescriptionProvider(的EntityType,attribute.MetadataClassType)的EntityType);
}
}
}



此验证程序的最大缺点分别为:




  • 它执行像蜗牛。如果你执行它在单一的实体,但如果你想用几百,几千或多个实体的工作问题很多也没关系。

  • 它不支持复杂类型出来的箱 - 你必须创建特殊的属性,并用它在元数据来验证复杂的类型,以及

  • 这是我用DataAnnotations任何业务验证最后一次。他们是UI验证最有用只有少数实体



用于验证复杂类型/嵌套的对象属性:

  ///<总结> 
///属性嵌套复杂类型的验证。
///< /总结>
[AttributeUsage(AttributeTargets.Property,的AllowMultiple = FALSE,继承= TRUE)]
公共密封类ValidateComplexTypeAttribute:ValidationAttribute
{
公众覆盖BOOL的IsValid(对象的值)
{
返回DataValidator.IsValid(值);
}
}


I'm using the ADO.Net Entity Framework. To handle input validation I'm trying to use DataAnnotations, I looked around on StavkOverflow and Google, and everywhere I found almost the same example of using MetadataType. However, I've been trying for hours and I cannot get it to work.. For some reason, the CustomAttributes from the EmployeeMetaData class are not being applied to the respective field/properties on the Employee class. Does anyone have any idea why this might be happening? And yes, I'm sure the property types and names match perfectly.

Any help is appreciated, I've been stuck on this for hours. Thanks in advance.

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<string> errors = (from v in property.GetCustomAttributes(true).OfType<ValidationAttribute>() 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;
    }
}

解决方案

I used this one (URLs points to helpful articles where I took some ideas):

// http://www.clariusconsulting.net/blogs/kzu/archive/2010/04/15/234739.aspx
/// <summary>
/// Validator provides helper methods to execute Data annotations validations
/// </summary>
public static class DataValidator
{
    /// <summary>
    /// Checks if whole entity is valid
    /// </summary>
    /// <param name="entity">Validated entity.</param>
    /// <returns>Returns true if entity is valid.</returns>
    public static bool IsValid(object entity)
    {
        AssociateMetadataType(entity);

        var context = new ValidationContext(entity, null, null);
        return Validator.TryValidateObject(entity, context, null, true);
    }

    /// <summary>
    /// Validate whole entity
    /// </summary>
    /// <param name="entity">Validated entity.</param>
    /// <exception cref="ValidationException">The entity is not valid.</exception>
    public static void Validate(object entity)
    {
        AssociateMetadataType(entity);

        var context = new ValidationContext(entity, null, null);
        Validator.ValidateObject(entity, context, true);
    }

    /// <summary>
    /// Validate single property of the entity.
    /// </summary>
    /// <typeparam name="TEntity">Type of entity which contains validated property.</typeparam>
    /// <typeparam name="TProperty">Type of validated property.</typeparam>
    /// <param name="entity">Entity which contains validated property.</param>
    /// <param name="selector">Selector for property being validated.</param>
    /// <exception cref="ValidationException">The value of the property is not valid.</exception>
    public static void ValidateProperty<TEntity, TProperty>(TEntity entity, Expression<Func<TEntity, TProperty>> 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);
    }

    /// <summary>
    /// Validate single property of the entity.
    /// </summary>
    /// <typeparam name="TEntity">Type of entity which contains validated property.</typeparam>
    /// <param name="entity">Entity which contains validated property.</param>
    /// <param name="memberName">Name of the property being validated.</param>
    /// <exception cref="InvalidOperationException">The entity does not contain property with provided name.</exception>
    /// <exception cref="ValidationException">The value of the property is not valid.</exception>
    public static void ValidateProperty<TEntity>(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<MetadataTypeAttribute>())
        {
            TypeDescriptor.AddProviderTransparent(
                new AssociatedMetadataTypeTypeDescriptionProvider(entityType, attribute.MetadataClassType), entityType);
        }
    }
}

The biggest disadvantages of this validator were:

  • It performs like a snail. It doesn't matter if you execute it on single entity but matter a lot if you want to work with hundreds, thousands or more entities.
  • It doesn't support complex types out of the box - you must create special attribute and use it in metadata to validate complex type as well
  • It was last time I used DataAnnotations for any business validation. They are mostly useful for UI validation only with few entities.

Attribute for validating complex type / nested object:

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

这篇关于C#从添加的EntityFramework到DataAnnotations实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆