EntityFramework 和 DataAnnotations,未显示错误

发布于 2024-11-28 01:20:56 字数 3638 浏览 2 评论 0原文

我正在使用实体框架并尝试使用数据注释进行验证。我在谷歌上查找了几个例子,发现到处都有相同的结构。我遵循了它,但由于某种原因我的错误没有显示在表格中。我知道,我可能必须使用 Validator 类手动验证属性,但我不知道在哪里执行此操作。我知道我可以侦听 PropertyChanging 事件,但这只传递属性的名称,而不传递即将分配的值。有人知道我该如何解决这个问题吗?

提前致谢。

[MetadataType(typeof(Employee.MetaData))]
public partial class Employee
{
    private sealed class MetaData
    {
        [Required(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; }
    }
}

xaml

<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="20" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
<fx:PasswordBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="20" Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />

编辑:(根据 Rachel 的评论实现了 IDataErrorInfo 类)

public static class EntityHelper
{
    public static string ValidateProperty(object instance, string propertyName)
    {
        PropertyInfo property = instance.GetType().GetProperty(propertyName);
        object value = property.GetValue(instance, null);
        List<string> errors = (from v in property.GetCustomAttributes(true).OfType<ValidationAttribute>() where !v.IsValid(value) select v.ErrorMessage).ToList();
        return (errors.Count > 0) ? String.Join("\r\n", errors) : null;
    }
}

[MetadataType(typeof(Employee.MetaData))]
public partial class Employee:IDataErrorInfo
{
    private sealed class MetaData
    {
        [Required(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; }
    }

    public string Error { get { return String.Empty; } }
    public string this[string property]
    {
        get { return EntityHelper.ValidateProperty(this, property); }
    }

xaml

<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />

I am using the entity framework and trying to use Data Annotations for validation. I have looked up several examples on google and found the same structure everywhere. I followed it, but for some reason my errors aren't showing up in the form. I know, I might have to validate the properties manually with the Validator class, but I cannot figure out where to do it. I know I can listen to the PropertyChanging event, but that only passes the name of the property, and not the value that is about to be assigned. Anyone have any ideas how I can get around this?

Thanks in advance.

[MetadataType(typeof(Employee.MetaData))]
public partial class Employee
{
    private sealed class MetaData
    {
        [Required(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; }
    }
}

the xaml

<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="20" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
<fx:PasswordBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="20" Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />

Edit: (implemented the IDataErrorInfo class based on Rachel's comment)

public static class EntityHelper
{
    public static string ValidateProperty(object instance, string propertyName)
    {
        PropertyInfo property = instance.GetType().GetProperty(propertyName);
        object value = property.GetValue(instance, null);
        List<string> errors = (from v in property.GetCustomAttributes(true).OfType<ValidationAttribute>() where !v.IsValid(value) select v.ErrorMessage).ToList();
        return (errors.Count > 0) ? String.Join("\r\n", errors) : null;
    }
}

[MetadataType(typeof(Employee.MetaData))]
public partial class Employee:IDataErrorInfo
{
    private sealed class MetaData
    {
        [Required(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; }
    }

    public string Error { get { return String.Empty; } }
    public string this[string property]
    {
        get { return EntityHelper.ValidateProperty(this, property); }
    }

the xaml

<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

維他命╮ 2024-12-05 01:20:56

我已经成功地实现了类似的场景,我强烈建议您查看它是如何在 http://waf 中实现的。 codeplex.com/。它使用实体框架和 WPF 的数据注释验证。

使用实体框架进行此操作时可能会遇到的一个重要问题是,数据注释验证器将忽略您的元数据,直到您在验证之前在代码中的某处添加 EntityObject 的元数据:

TypeDescriptor.AddProviderTransparent(new 
    AssociatedMetadataTypeTypeDescriptionProvider(typeof(EntityObject)), 
    typeof(EntityObject));

附加信息:
使用验证器时忽略 .NET 4 RTM MetadataType 属性

另外,我认为您的元数据应该是公开的而不是密封的。

以下是 DataErrorInfoSupport.cs 的摘录,以供快速参考:

    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
    public string Error { get { return this[""]; } }

    /// <summary>
    /// Gets the error message for the property with the given name.
    /// </summary>
    /// <param name="memberName">The name of the property whose error message to get.</param>
    /// <returns>The error message for the property. The default is an empty string ("").</returns>
    public string this[string memberName]
    {
        get
        {
            List<ValidationResult> validationResults = new List<ValidationResult>();

            if (string.IsNullOrEmpty(memberName))
            {
                Validator.TryValidateObject(instance, new ValidationContext(instance, null, null), validationResults, true);
            }
            else
            {
                PropertyDescriptor property = TypeDescriptor.GetProperties(instance)[memberName];
                if (property == null)
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                        "The specified member {0} was not found on the instance {1}", memberName, instance.GetType()));
                }
                Validator.TryValidateProperty(property.GetValue(instance),
                    new ValidationContext(instance, null, null) { MemberName = memberName }, validationResults);
            }

            StringBuilder errorBuilder = new StringBuilder();
            foreach (ValidationResult validationResult in validationResults)
            {
                errorBuilder.AppendInNewLine(validationResult.ErrorMessage);
            }

            return errorBuilder.ToString();
        }
    }

I've succesfully implemented similar scenario and I strongly suggest you to look at how it has been implemented in http://waf.codeplex.com/. It uses Data Annotations validation with Entity Framework and WPF.

One significant issue you might have with making this work with Entity Framework is that Data Annotations Validator will ignore your metadata until you Add metadata for EntityObject somewhere in your code before validating:

TypeDescriptor.AddProviderTransparent(new 
    AssociatedMetadataTypeTypeDescriptionProvider(typeof(EntityObject)), 
    typeof(EntityObject));

Additional information:
.NET 4 RTM MetadataType attribute ignored when using Validator

Also, I think that your metadata should be public and not sealed.

Here is an excerpt from DataErrorInfoSupport.cs, for quick reference:

    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
    public string Error { get { return this[""]; } }

    /// <summary>
    /// Gets the error message for the property with the given name.
    /// </summary>
    /// <param name="memberName">The name of the property whose error message to get.</param>
    /// <returns>The error message for the property. The default is an empty string ("").</returns>
    public string this[string memberName]
    {
        get
        {
            List<ValidationResult> validationResults = new List<ValidationResult>();

            if (string.IsNullOrEmpty(memberName))
            {
                Validator.TryValidateObject(instance, new ValidationContext(instance, null, null), validationResults, true);
            }
            else
            {
                PropertyDescriptor property = TypeDescriptor.GetProperties(instance)[memberName];
                if (property == null)
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                        "The specified member {0} was not found on the instance {1}", memberName, instance.GetType()));
                }
                Validator.TryValidateProperty(property.GetValue(instance),
                    new ValidationContext(instance, null, null) { MemberName = memberName }, validationResults);
            }

            StringBuilder errorBuilder = new StringBuilder();
            foreach (ValidationResult validationResult in validationResults)
            {
                errorBuilder.AppendInNewLine(validationResult.ErrorMessage);
            }

            return errorBuilder.ToString();
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文