C# 具有动态数据的自定义高级实体验证
我正在寻找一种解决方案,当用户使用实体框架在动态数据屏幕中保存其更改时,可以执行一些自定义实体验证(这需要数据库访问、跨成员验证…) 验证比我对属性所能做的更复杂(它需要访问数据库等) 您能拦截SaveChanges调用吗?C# 具有动态数据的自定义高级实体验证,c#,entity-framework,validation,asp.net-dynamic-data,C#,Entity Framework,Validation,Asp.net Dynamic Data,我正在寻找一种解决方案,当用户使用实体框架在动态数据屏幕中保存其更改时,可以执行一些自定义实体验证(这需要数据库访问、跨成员验证…) 验证比我对属性所能做的更复杂(它需要访问数据库等) 您能拦截SaveChanges调用吗? 我试图重写DbContext对象中的ValidateEntity,但动态数据似乎没有调用它(可能是因为它使用的是内部ObjectContext,不知道为什么),重写SaveChanges也没有帮助。 我没有看到任何我可以订阅的活动 报告应有助于: 通过重写 OnValida
我试图重写DbContext对象中的
ValidateEntity
,但动态数据似乎没有调用它(可能是因为它使用的是内部ObjectContext,不知道为什么),重写SaveChanges也没有帮助。我没有看到任何我可以订阅的活动 报告应有助于: 通过重写 OnValidate方法或处理已调用的验证事件 更改任何数据字段时。这种方法允许您添加验证 以及单个字段的业务逻辑。这种方法更为有效 常规,而不是为单个字段添加验证。这是有用的 当相同的验证逻辑可以应用于多个数据时 领域它还允许您执行涉及以下内容的验证检查: 多个字段 但是我使用的是POCO实体框架6类,因此没有要重写的
OnValidate
方法,从我读到的内容来看,这是针对LinqToSql的,我找不到他们提到的Validate
事件
我试图在DbContext的构造函数中订阅内部ObjectContext
的SavingChanges
事件,以手动调用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.");
if(entity.IsValidForAddOrUpdate())
{
db.Set().Add(实体);
db.SaveChanges()
}
否则抛出新的DbValidationException(“由于规则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();
}
另请参见以使其与DataAnnotation一起工作
你写道:
如果我抛出DbEntityValidationException(或ValidationException
正如本文所建议的那样),ASPNET可以像处理任何异常一样处理它
(黄色屏幕)
看。调用SaveChanges
时,需要捕获DbEntityValidationException
(或ValidationException
),如果不捕获它们以在控制器内处理它们,则默认错误处理程序将处理它们
或者,您可以使用控件捕获ValidationException:
<!-- Capture validation exceptions -->
<asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1"
runat="server" />
请参阅。我发现了一个我不喜欢的解决方法,但它很有效:
我的上下文仍在执行验证,并在必要时抛出ValidationException
由于ListView
似乎无法捕获和处理异常,我自己通过处理ListView
的OnItemUpdated
或oniminserted
事件来实现这一点:
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 });
}
}
我同意这一说法,我还认为业务逻辑不应该与实体frameworkIt的可论证性相耦合。也许域层对象可以进行验证。只要不使用糟糕的“EF前面的存储库层”模式……我同意,但动态数据并没有提供很多验证选项。但问题不在这里,问题是DbValidationException没有被DynamicValidator捕获(尽管我找到的文档和文章说应该这样),所以我得到了一个黄色屏幕。现在我甚至不想拥有一个好的体系结构,只是想拥有一些可以工作的东西:(.是的,我发现了什么,但是DynamicValidator没有捕获异常,我不知道为什么。如果我调试,我看到它进入ValidateException方法,它似乎检测到它并用它做事情(),但异常仍然会出现在默认错误处理程序上。我甚至尝试了Dynamic Data Futures包中的改进的DynamicValidator,但它也不起作用。我无法在控制器中捕获它,因为没有动态数据。我看到了,有趣的问题,如果同时没有得到回答,我将在周四查看它。