ASP.NET MVC和ADO.NET实体框架中的最佳实践实体验证

时间:2021-03-05 21:18:19

i am using ASP.NET MVC & ADO.NET Entity Framework in a project. I want to add validation logic to my entities via partial classes. It works similar like shown in the NerdDinner.com ASP.NET MVC Application which is using LINQ2SQL. The main difference is, that i have to use the"OnPropertyChanging" event instead the "OnValidating" like in LINQ2SQL.

我在一个项目中使用ASP.NET MVC和ADO.NET Entity Framework。我想通过部分类向我的实体添加验证逻辑。它的工作方式类似于使用LINQ2SQL的NerdDinner.com ASP.NET MVC应用程序。主要区别在于,我必须使用“OnPropertyChanging”事件而不是LINQ2SQL中的“OnValidating”。

There are some problems when doing it that way: - The "OnPropertyChanging" event is not the optimal point of calling validation logic, because it always triggers, even on creating a calling the default constructor. This really can cause serious problems (not only performance problems). - Together with the MVC framework there are problems when using the "EntityState.Detached" (i couldn't find any other way) to determine if a entity needs to be validated or not. Because a entity loses its entity sate during it gets displayed in the view (because on POST-event a new entity object is created instead of returning the original one).

这样做有一些问题: - “OnPropertyChanging”事件不是调用验证逻辑的最佳点,因为它总是触发,即使在创建调用默认构造函数时也是如此。这确实会导致严重的问题(不仅仅是性能问题)。 - 与MVC框架一起使用“EntityState.Detached”(我找不到任何其他方法)来确定是否需要验证实体时会出现问题。因为实体在视图中显示时会丢失其实体状态(因为在POST事件中创建新的实体对象而不是返回原始实体对象)。

My question is: Is there a better way of adding validation to ADO.NET Entities? I couldn't find any tutorials using a practical way of adding validation to ADO.NET Entities.

我的问题是:有没有更好的方法向ADO.NET实体添加验证?我找不到任何使用向ADO.NET实体添加验证的实用方法的教程。

4 个解决方案

#1


Personally, I don't put validation in the objects themselves. I use the xVal library to handle my entity validation.

就个人而言,我没有在对象本身中进行验证。我使用xVal库来处理我的实体验证。

xVal encourages you to annotate your entity classes (or, actually, metadata companion classes) with attributes that describe the various validation rules. These validation attributes are the default ones that come with .NET in System.ComponentModel.DataAnnotations.

xVal鼓励您使用描述各种验证规则的属性来注释您的实体类(或实际上是元数据伴随类)。这些验证属性是System.ComponentModel.DataAnnotations中.NET附带的默认属性。

You then run validation against your objects manually in your business layer. This is done by using a method that runs the System.ComponentModel.DataAnnotations validation logic. I wrote one that looks like this:

然后,您可以在业务层中手动对对象运行验证。这是通过使用运行System.ComponentModel.DataAnnotations验证逻辑的方法来完成的。我写了一个看起来像这样的:

/// <summary>
/// Gets the validation errors for the passed in object by using reflection to retrieve the 
/// <see cref="ValidationAttribute"/>s placed on its properties or on the properties of the object's
/// metadata class (as specified by a <see cref="MetadataTypeAttribute"/> placed on the object's class)
/// </summary>
/// <param name="instance">The object to validate</param>
/// <returns>Any validation errors</returns>
/// <remarks>
/// Borrowed (and cleaned up) from
/// http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/
/// </remarks>
public static IEnumerable<ErrorInfo> Validate(object instance)
{
    //Try to get the MetadataType attribute from the object
    MetadataTypeAttribute metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();

    //If the MetadataType attribute existed, get the metadata class
    //else just use the class of the object
    Type buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();

    IEnumerable<PropertyDescriptor> buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
    IEnumerable<PropertyDescriptor> modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();

    //This query matches each property on the model class against the buddy class
    //gets a list of all invalid validation attributes and returns a list of
    //validation errors
    return from buddyProp in buddyClassProperties
           join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name
           from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
           where !attribute.IsValid(modelProp.GetValue(instance))
           select new ErrorInfo(buddyProp.Name, attribute.FormatErrorMessage(String.Empty), instance);
}

xVal provides a neat exception type you can throw that encapsulates validation errors and allows you to easily add them to the ModelState in your Controller.

xVal提供了一个可以抛出的简洁异常类型,它封装了验证错误,并允许您轻松地将它们添加到Controller中的ModelState中。

xVal also will autogenerate client-side JavaScript form validation code for you by leveraging jQuery.Validate by providing an HtmlHelper method.

xVal还将通过提供HtmlHelper方法利用jQuery.Validate为您自动生成客户端JavaScript表单验证代码。

Check out http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/ for a walkthrough on how it works. I've found it to be very nice way of doing validation that's not a total chore. It fits right in in the ASP.NET MVC way of doing things.

查看http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/,了解其工作原理。我发现这是一种非常好的验证方式,这不是一项繁琐的工作。它适合ASP.NET MVC的工作方式。

#2


Personally, I don't use the OnXChanging partial. You'd have to have another partial class for the entity that did something for that method signature.

就个人而言,我不使用OnXChanging部分。您必须为该方法签名执行某些操作的实体设置另一个部分类。

I have one centralised save, (either by a helper method for that entity, or a save on a repository pattern implementation for that entity) where I validate the values meet my criteria before performing my context.SaveChanges().

我有一个集中保存(通过该实体的辅助方法,或者对该实体的存储库模式实现的保存),我在执行context.SaveChanges()之前验证值是否符合我的条件。

Nor would I use the onpropertychanging event for validation, if I have a centralised save, then I only need to validate in one place, I would leave that for specific triggers at other points. (Like if user changed X then update Y)

我也不会使用onpropertychanging事件进行验证,如果我有一个集中保存,那么我只需要在一个地方进行验证,我会将其留给其他点的特定触发器。 (如果用户更改了X则更新Y)

#3


One simple way to validate EF entity objects, is to use DataAnnotations on your model classes. There a two obvious benefit of this approach. One is that the same validation logic can be reused in many views such as edit and create. And the other is that when data annotations are available in our entity classes, ASP.NET MVC provides for implementing both client side and server side validation out of the box without much fixtures and coding.

验证EF实体对象的一种简单方法是在模型类上使用DataAnnotations。这种方法有两个明显的好处。一个是可以在许多视图中重用相同的验证逻辑,例如编辑和创建。另一个是当我们的实体类中有数据注释时,ASP.NET MVC提供了开箱即用的客户端和服务器端验证,而没有太多的夹具和编码。

This http://theminimalistdeveloper.com/2010/07/23/how-to-do-client-side-validation-in-asp-net-mvc-2/ shows in simple steps how this can be achieved in EF 4.0

这个http://theminimalistdeveloper.com/2010/07/23/how-to-do-client-side-validation-in-asp-net-mvc-2/以简单的步骤显示了如何在EF 4.0中实现这一点

#4


Have you looked into IValidatableObject implementation. I am not sure if this answers your question; however, with this your validation stays with your domain object.

你有没有看过IValidatableObject实现。我不确定这是否能回答你的问题;但是,使用此功能,您的验证将保留在您的域对象中。

More about it with example is at: How do I use IValidatableObject?

更多关于它的例子是:我如何使用IValidatableObject?

DataAnnotations are there for running normal validations; however, if there are complex validations, you can created your own ValidationAttribute or implement IValidatableObject. If you go this route, you can use combination of both. I generally do that.

DataAnnotations用于运行正常验证;但是,如果存在复杂的验证,则可以创建自己的ValidationAttribute或实现IValidatableObject。如果你走这条路,你可以使用两者的组合。我通常这样做。

#1


Personally, I don't put validation in the objects themselves. I use the xVal library to handle my entity validation.

就个人而言,我没有在对象本身中进行验证。我使用xVal库来处理我的实体验证。

xVal encourages you to annotate your entity classes (or, actually, metadata companion classes) with attributes that describe the various validation rules. These validation attributes are the default ones that come with .NET in System.ComponentModel.DataAnnotations.

xVal鼓励您使用描述各种验证规则的属性来注释您的实体类(或实际上是元数据伴随类)。这些验证属性是System.ComponentModel.DataAnnotations中.NET附带的默认属性。

You then run validation against your objects manually in your business layer. This is done by using a method that runs the System.ComponentModel.DataAnnotations validation logic. I wrote one that looks like this:

然后,您可以在业务层中手动对对象运行验证。这是通过使用运行System.ComponentModel.DataAnnotations验证逻辑的方法来完成的。我写了一个看起来像这样的:

/// <summary>
/// Gets the validation errors for the passed in object by using reflection to retrieve the 
/// <see cref="ValidationAttribute"/>s placed on its properties or on the properties of the object's
/// metadata class (as specified by a <see cref="MetadataTypeAttribute"/> placed on the object's class)
/// </summary>
/// <param name="instance">The object to validate</param>
/// <returns>Any validation errors</returns>
/// <remarks>
/// Borrowed (and cleaned up) from
/// http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/
/// </remarks>
public static IEnumerable<ErrorInfo> Validate(object instance)
{
    //Try to get the MetadataType attribute from the object
    MetadataTypeAttribute metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();

    //If the MetadataType attribute existed, get the metadata class
    //else just use the class of the object
    Type buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();

    IEnumerable<PropertyDescriptor> buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
    IEnumerable<PropertyDescriptor> modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();

    //This query matches each property on the model class against the buddy class
    //gets a list of all invalid validation attributes and returns a list of
    //validation errors
    return from buddyProp in buddyClassProperties
           join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name
           from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
           where !attribute.IsValid(modelProp.GetValue(instance))
           select new ErrorInfo(buddyProp.Name, attribute.FormatErrorMessage(String.Empty), instance);
}

xVal provides a neat exception type you can throw that encapsulates validation errors and allows you to easily add them to the ModelState in your Controller.

xVal提供了一个可以抛出的简洁异常类型,它封装了验证错误,并允许您轻松地将它们添加到Controller中的ModelState中。

xVal also will autogenerate client-side JavaScript form validation code for you by leveraging jQuery.Validate by providing an HtmlHelper method.

xVal还将通过提供HtmlHelper方法利用jQuery.Validate为您自动生成客户端JavaScript表单验证代码。

Check out http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/ for a walkthrough on how it works. I've found it to be very nice way of doing validation that's not a total chore. It fits right in in the ASP.NET MVC way of doing things.

查看http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/,了解其工作原理。我发现这是一种非常好的验证方式,这不是一项繁琐的工作。它适合ASP.NET MVC的工作方式。

#2


Personally, I don't use the OnXChanging partial. You'd have to have another partial class for the entity that did something for that method signature.

就个人而言,我不使用OnXChanging部分。您必须为该方法签名执行某些操作的实体设置另一个部分类。

I have one centralised save, (either by a helper method for that entity, or a save on a repository pattern implementation for that entity) where I validate the values meet my criteria before performing my context.SaveChanges().

我有一个集中保存(通过该实体的辅助方法,或者对该实体的存储库模式实现的保存),我在执行context.SaveChanges()之前验证值是否符合我的条件。

Nor would I use the onpropertychanging event for validation, if I have a centralised save, then I only need to validate in one place, I would leave that for specific triggers at other points. (Like if user changed X then update Y)

我也不会使用onpropertychanging事件进行验证,如果我有一个集中保存,那么我只需要在一个地方进行验证,我会将其留给其他点的特定触发器。 (如果用户更改了X则更新Y)

#3


One simple way to validate EF entity objects, is to use DataAnnotations on your model classes. There a two obvious benefit of this approach. One is that the same validation logic can be reused in many views such as edit and create. And the other is that when data annotations are available in our entity classes, ASP.NET MVC provides for implementing both client side and server side validation out of the box without much fixtures and coding.

验证EF实体对象的一种简单方法是在模型类上使用DataAnnotations。这种方法有两个明显的好处。一个是可以在许多视图中重用相同的验证逻辑,例如编辑和创建。另一个是当我们的实体类中有数据注释时,ASP.NET MVC提供了开箱即用的客户端和服务器端验证,而没有太多的夹具和编码。

This http://theminimalistdeveloper.com/2010/07/23/how-to-do-client-side-validation-in-asp-net-mvc-2/ shows in simple steps how this can be achieved in EF 4.0

这个http://theminimalistdeveloper.com/2010/07/23/how-to-do-client-side-validation-in-asp-net-mvc-2/以简单的步骤显示了如何在EF 4.0中实现这一点

#4


Have you looked into IValidatableObject implementation. I am not sure if this answers your question; however, with this your validation stays with your domain object.

你有没有看过IValidatableObject实现。我不确定这是否能回答你的问题;但是,使用此功能,您的验证将保留在您的域对象中。

More about it with example is at: How do I use IValidatableObject?

更多关于它的例子是:我如何使用IValidatableObject?

DataAnnotations are there for running normal validations; however, if there are complex validations, you can created your own ValidationAttribute or implement IValidatableObject. If you go this route, you can use combination of both. I generally do that.

DataAnnotations用于运行正常验证;但是,如果存在复杂的验证,则可以创建自己的ValidationAttribute或实现IValidatableObject。如果你走这条路,你可以使用两者的组合。我通常这样做。