使用动态数据进行自定义高级实体验证



我正在寻找一种解决方案,当用户使用实体框架
将其更改保存在动态数据屏幕中时,执行一些自定义实体验证(这需要数据库访问、跨成员验证......验证比我对属性可以做的事情更复杂(它需要访问数据库等)

你能拦截保存更改调用吗?
我试图覆盖 DbContext 对象中的ValidateEntity,但动态数据似乎没有调用它(可能是因为它使用的是内部 ObjectContext,不知道为什么),覆盖 SaveChanges 也无济于事。
我没有看到任何我可以订阅的活动...

文档应该有帮助:

通过覆盖 OnValidate 方法或处理 Validate 事件,这些事件被调用 当任何数据字段发生更改时。此方法允许您添加验证 以及单个字段的业务逻辑。这种方法更多 比为单个字段添加验证更通用。它很有用 当相同的验证逻辑可以应用于多个数据时 田。它还允许您执行涉及的验证检查 多个字段。

但是我使用的是 POCO 实体框架 6 类,因此没有OnValidate方法可以重写,从我读到的内容来看,这是针对 LinqToSql 的,我找不到他们提到的Validate事件。

我尝试在 DbContext 的构造函数中订阅内部ObjectContextSavingChanges 事件,以手动调用 ValidateEntity ,但我不知道如何处理结果。如果我抛出一个DbEntityValidationException(或本文中建议的ValidationException),ASPNET 会像处理任何异常(黄屏)一样处理它。

实现IValidatableObject也不起作用。

我也尝试实现我自己的DynamicValidator看看会发生什么,但没有成功,它似乎处理了异常(如果我覆盖ValidateException,并放置一个断点,我会看到它),但它仍然冒泡到默认错误处理程序并显示黄色屏幕。我一定错过了什么。

那么,您应该如何执行复杂的验证(跨字段、查询等) 在保存在动态数据/EF中之前在实体上?

我认为

像你试图执行的逻辑不属于你的架构中的这样一个级别。让数据库强制执行它应该执行的约束,如外键等,并使您的业务逻辑在上面一层。例如,在要验证的实体上,可以添加一个IsValidForAddOrUpdate()方法,该方法包含您无论如何都会放入验证程序的逻辑。然后只需利用新方法:

if (entity.IsValidForAddOrUpdate())
{
    db.Set<Entity>().Add(entity);
    db.SaveChanges()
}
else throw new DbValidationException("Entity failed validation due to rule xyz.");

实现这一点的一种方法是在您的实体上实现IDataErrorInfo接口,如下所示:

public partial class MyEntity : IDataErrorInfo
{
    public MyEntity()
    {
    }
    ...
    #region IDataErrorInfo Members
    public string Error
    {
        get { throw new NotImplementedException(); }
    }
    public string this[string propertyName]
    {
        get
        {
            //Custom Validation logic
            return  MyValidator.ValidateProperty(this, propertyName);
        }
    }
    #endregion  
}

要从 IDataErrorInfo 方法访问当前的 DBContext,您可以使用此答案。然后重写上下文的 SaveChanges 方法:

    public override int SaveChanges()
    {
        this.ObjectContext.DetectChanges();
        // Get all the new and updated objects
        var objectsToValidate =
        ChangeTracker.Entries().Where(x => x.State == EntityState.Modified || x.State == EntityState.Added).
        Select(e => e.Entity);
        // Check each object for errors
        foreach (var obj in objectsToValidate)
        {
            if (obj is IDataErrorInfo)
            {
                // Check each property
                foreach (var property in obj.GetType().GetProperties())
                {
                    var columnError = (obj as IDataErrorInfo)[property.Name];
                    if (columnError != null) {
                    //Handle your validation errors
                    throw new DbEntityValidationException(columnError); }
                }
            }
        }
        return base.SaveChanges();
    }

另请参阅此答案以使其与数据注释一起使用。

你写道:

如果我抛出一个 DbEntityValidationException(或 ValidationException) 就像本文建议的那样),ASPNET 像处理任何异常一样处理它 (黄屏)。

看到这个答案。当您调用SaveChanges时,您需要捕获DbEntityValidationException(或ValidationException),如果您没有捕获它们以在控制器中处理它们,则它们由默认错误处理程序处理。

或者,您可以使用 DynamicValidator 控件来捕获 ValidationExceptions:

    <!-- Capture validation exceptions -->
    <asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1" 
        runat="server" /> 

DynamicValidator的问题在于它需要ControlToValidate属性,并且仅捕获来自该控件的异常。此外,封装在其他异常中的异常可能会造成问题。有一种解决方法 - 您可以从DynamicValidator继承并覆盖其ValidateException方法,请参阅此博客。

请参阅此文章。

我发现了一个我不喜欢的解决方法,但它有效:

我的上下文仍在执行验证,并在必要时抛出ValidationException

由于ListView似乎没有捕获和处理异常,因此我通过处理ListViewOnItemUpdatedOnItemInserted事件来自己执行此操作:

protected void ListView1_ItemUpdated(object sender, ListViewUpdatedEventArgs e)
{
    if (e.Exception != null)
    {
        ValidationError.DisplayError(e.Exception.Message);
        e.ExceptionHandled = true;
        e.KeepInEditMode = true;
    }
}

ValidationError用于将异常消息添加到验证摘要中。它添加了一个"假的",总是验证器与消息失败。

public class ValidationError : BaseValidator
{
    private ValidationError(string message)
        : base()
    {
        ErrorMessage = message;
        IsValid = false;
    }
    protected override bool EvaluateIsValid()
    {
        return false;
    }
    public static void DisplayError(string message, string validationGroup)
    {
        var currentPage = HttpContext.Current.Handler as Page;
        currentPage.Validators.Add(new ValidationError(message) { ValidationGroup = validationGroup });
    }
}

相关内容

  • 没有找到相关文章

最新更新