2016-04-28 2 views
12

Я ищу решение для выполнения некоторой выборочной проверки подлинности объекта (для чего потребуется доступ к базе данных, проверка перекрестных позиций ...), когда пользователь сохраняет свои изменения на экране динамических данных, с Entity Framework.
Валидация более сложна, чем то, что я могу сделать с атрибутами (для этого требуется доступ к базе данных и т. Д.)Пользовательская расширенная проверка сущностей с динамическими данными

Можете ли вы перехватить вызов SaveChanges?
Я попытался переопределить ValidateEntity в объекте DbContext, но Dynamic Data, похоже, не вызывает его (возможно, потому, что он использует внутренний ObjectContext, не уверен, почему), и переопределение SaveChanges тоже не помогает.
Я не вижу никакого события, которое я мог бы подписаться ...

documentation должен помочь:

проверки Настройки для отдельного поля данных пути переопределения OnValidate метода или обработки события Validate , которые вызывают при изменении любого поля данных. Этот подход позволяет добавить валидацию и бизнес-логику для отдельного поля. Этот подход больше , чем добавление валидации для отдельного поля. Полезно , когда одна и та же логика проверки может применяться к нескольким данным . Он также позволяет выполнять проверки проверки, которые включают в себя несколько полей.

Но я использую POCO Entity Framework 6 классов, так что нет OnValidate метода, чтобы переопределить, и от того, что я прочитал это для LinqToSql, и я не могу найти Validate события они упоминают.

Я попытался подписаться на SavingChanges случае в конструкторе моего DbContext внутренней ObjectContext, вызвать вручную в ValidateEntity, но я не знаю, что делать с результатом. Если я выброшу DbEntityValidationException (или ValidationException, как предлагается в this article), ASPNET обрабатывает его как любое исключение (желтый экран).

Реализация IValidatableObject не работает.

Я также попытался реализации моей DynamicValidator, чтобы посмотреть, что происходит, но без успеха, он, кажется, обрабатывает исключение (если переопределить ValidateException, и поставить точку останова, я это вижу), но это все еще клокотало до дефолта обработчик ошибок и отображает желтый экран. Я должен что-то упустить.

Итак, как вы должны выполнять комплексную проверку (кросс-поле, с запросами и т. Д.) На объектах перед сохранением в динамических данных/EF?

ответ

0

Я нашел обходной путь, мне не нравится, но она работает:

Мой контекст по-прежнему выполняет проверку и бросает ValidationException при необходимости.

Как ListView, кажется, не поймать и обработать исключение, я делаю это сам по обработке OnItemUpdated или OnItemInserted события ListView:

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 }); 
    } 
} 
4

Я бы сказал, что логика, как вы пытаетесь выполнить, не имеет такого уровня в вашей архитектуре. Пусть база данных обеспечивает ограничения, которые она должна использовать, например, внешние ключи и т. Д., И иметь свою бизнес-логику выше. Например, в вашей организации, которую вы хотите проверить, вы можете добавить метод IsValidForAddOrUpdate(), который в любом случае содержит логику, которую вы поместили в ваши валидаторы.Тогда просто использовать новые методы:

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

я согласен с этим утверждением, я также считаю, что бизнес-логика не должна быть соединена с каркасом объекта – Eldho

+1

Это спорно. Возможно, объект домена может иметь проверку. До тех пор, пока ужасный шаблон «хранилища перед шаблоном EF» не используется ... – James

+0

Согласен, но Dynamic Data не дает много вариантов проверки. Но проблемы не существует, проблема в том, что DbValidationException не поймано DynamicValidator (хотя документы и статьи, которые я нахожу, говорят, что это должно), поэтому я получаю желтый экран. Прямо сейчас я даже не пытаюсь иметь хорошую архитектуру, просто чтобы иметь что-то, что работает :( –

3

Один из способов, как для того чтобы достигнуть этого можно было бы реализации 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 
} 

Чтобы получить доступ к текущей DbContext из методов IDataErrorInfo вы можете использовать this answer. Затем переопределить метод SaveChanges вашего для Context:

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(); 
    } 

Смотрите также this answer, чтобы заставить его работать с DataAnnotations.

Вы писали:

Если я бросить DbEntityValidationException (или ValidationException , как предложено в этой статье), ASPNET обрабатывать ее как любое исключение (желтый экран).

См. this answer. Когда вы вызываете SaveChanges, вам нужно поймать DbEntityValidationException (или ValidationException), если вы не поймаете их для обработки их в своем контроллере, они обрабатываются обработчиком ошибок по умолчанию.

Или вы можете использовать DynamicValidator управления, чтобы поймать ValidationExceptions:

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

Проблемы DynamicValidator в том, что она требует ControlToValidate собственности и ловит только исключение, поступающее из этого элемента управления. Кроме того, исключения, заключенные в другие исключения, могут создавать проблемы. Существует обходное решение - вы можете наследовать от DynamicValidator и переопределить его метод ValidateExceptionsee this blog.

См. this article.

+0

Да, именно то, что я нашел, но DynamicValidator не поймает Исключение, я не знаю почему. Я отлаживаю, я вижу, что он вступает в метод ValidateException и, кажется, обнаруживает его и делает с ним что-то ([исходный код] (http://referencesource.microsoft.com/#System.Web.DynamicData/DynamicData/DynamicValidator. cs, a9f61764351be893, ссылки)), но Exception по-прежнему подходит к обработчику ошибок по умолчанию. Я даже попробовал ImprovedDynamicValidator из пакета Dynamic Data Futures, но он тоже не работает. Я не могу его поймать Контроллер, так как их нет с динамическими данными. –

+0

Я вижу, интересная проблема, я посмотрю на нее в четверг, если она не получит ответа между тем. –

Смежные вопросы