ASP.NET MVC和ADO.NET Entity Framework中的最佳实践实体验证

3
我正在一个项目中使用ASP.NET MVC和ADO.NET Entity Framework。我想通过partial classes为我的实体添加验证逻辑,这与使用LINQ2SQL的NerdDinner.com ASP.NET MVC Application类似。主要区别在于,我必须使用"OnPropertyChanging"事件而不是在LINQ2SQL中使用的"OnValidating"事件。
这种方式存在一些问题: - "OnPropertyChanging"事件不是调用验证逻辑的最佳时间点,因为它总是会触发,即使在创建默认构造函数时也是如此。这可能会导致严重问题(不仅是性能问题)。 - 在与MVC框架一起使用时,使用"EntityState.Detached"(我找不到其他方法)来确定实体是否需要进行验证时会出现问题。因为当实体在视图中显示时,它失去了实体状态(因为在POST事件中,会创建一个新的实体对象而不是返回原始实体对象)。
我的问题是:有没有更好的方法将验证添加到ADO.NET Entities中?我找不到使用实际方法将验证添加到ADO.NET Entities的任何教程。
4个回答

4

个人而言,我不会在对象本身中放置验证。我使用xVal库来处理实体验证。

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

然后,在业务层手动运行对象的验证。这是通过使用运行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提供了一个整洁的异常类型,您可以抛出该类型来封装验证错误,并允许您轻松地将它们添加到控制器中的ModelState中。
xVal还通过提供HtmlHelper方法利用jQuery.Validate自动生成客户端JavaScript表单验证代码。
请查看 http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/ 以获取有关其工作原理的详细信息。我发现这是一种非常好的验证方式,不会让人感到非常繁琐。它完全符合ASP.NET MVC的做事方式。

值得注意的是,这是为了在MVC v1中获得注释验证而必要的。由于MVC v2中内置了数据注释验证,因此您不需要xVal。 - Daniel Chambers

1

个人而言,我不使用OnXChanging部分类。您需要为实体拥有另一个部分类来处理该方法签名的操作。

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

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


1
OnXChangeing 不是一个事件,你是对的。但是 OnPropertyChanging 是一个事件。 - Alexander
是的,OnPropertyChanged 是一个很好的中央事件。但你仍然有一个问题,即验证会不必要地触发很多次。EventState.Detached 在 ASP.NET MVC 中无法使用,因为它会丢失...这就是为什么 Web 应用程序是“无状态”的原因 :-) - Alexander
没错,这就是为什么我会使用某种存储库模式来很好地分离业务对象/重新附加到EF。 - NikolaiDante

0

你有没有研究过IValidatableObject的实现?我不确定这是否回答了你的问题;但是,使用它可以使你的验证与你的领域对象保持一致。

更多关于它的例子在这里: 如何使用IValidatableObject?

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


1
这在DataAnnotations中运作良好。此外,如果有任何DataAnnotations验证错误,框架会短路并且不会调用Validate方法。 - r2018

0

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

这篇文章http://theminimalistdeveloper.com/2010/07/23/how-to-do-client-side-validation-in-asp-net-mvc-2/以简单的步骤展示了如何在EF 4.0中实现此功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接