2016-04-28 24 views
12

Poszukuję rozwiązania do przeprowadzenia niestandardowej weryfikacji jednostek (która wymagałaby dostępu do bazy danych, sprawdzenia dla wielu elementów ...), gdy użytkownik zapisuje zmiany na ekranie danych dynamicznych, z Entity Framework.
Sprawdzanie poprawności jest bardziej złożone niż to, co mogę zrobić z atrybutami (wymaga dostępu do bazy danych itp.).Niestandardowa zaawansowana walidacja jednostek za pomocą Dynamic Data

Czy możesz przechwycić wywołanie SaveChanges?
Próbowałem przesłonić obiekt ValidateEntity w obiekcie DbContext, ale dane dynamiczne nie wydają się go wywoływać (prawdopodobnie dlatego, że używa wewnętrznego obiektu ObjectContext, nie wiem dlaczego), a zastępowanie zmian SaveChanges również nie pomaga.
nie widzę żadnego zdarzenia, które mogłoby mi subskrypcji ...

documentation powinno pomóc:

walidacji Dostosuj dla pojedynczego pola danych poprzez nadpisanie metody OnValidate lub obsługi zdarzeń Weryfikuj , które są wywoływane po zmianie dowolnego pola danych. To podejście umożliwia dodanie sprawdzania poprawności i logiki biznesowej dla pojedynczego pola. To podejście jest bardziej ogólne niż dodawanie walidacji dla pojedynczego pola. Jest użyteczny , gdy tę samą logikę walidacji można zastosować do więcej niż jednego pola danych . Umożliwia także przeprowadzanie sprawdzania poprawności obejmujących wiele pól.

Ale używam POCO Entity Framework 6 klas, więc nie ma OnValidate sposób zastąpić, iz tego co czytałem to dla LinqToSql, i nie mogę znaleźć imprezę Validate wspominają.

Próbowałam zapisać się do imprezy SavingChanges wewnętrznej ObjectContext w konstruktorze mojego DbContext, aby zadzwonić do ValidateEntity ręcznie, ale nie wiem, co zrobić z wyniku. Jeśli wyrzucę DbEntityValidationException (lub ValidationException jak sugerowano w this article), ASPNET traktuje go jak każdy wyjątek (żółty ekran).

Implementacja IValidatableObject również nie działa.

Próbowałem również wdrożyć własne DynamicValidator, aby zobaczyć, co się dzieje, ale bez powodzenia, wydaje się, że obsługuje wyjątek (jeśli przesłonię ValidateException, i umieścić punkt przerwania, widzę to), ale nadal jest bąbelkowane do domyślnego obsługa błędów i wyświetla żółty ekran. Muszę czegoś przegapić.

Jak zatem wykonać kompleksową walidację (cross-field, z zapytaniami itp.) Na encji przed zapisaniem w Dynamic Data/EF?

Odpowiedz

0

znalazłem obejście mi się nie podoba, ale to działa:

Moja kontekście jest jeszcze wykonanie walidacji i rzuca ValidationException w razie potrzeby.

Jako ListView nie wydaje się złapać i obsłużyć wyjątek, robię to sam, obsługując zdarzenie OnItemUpdated lub OnItemInserted z 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 służy do dodawania wiadomości wyjątek od Podsumowanie sprawdzania poprawności. Dodaje "fałszywy", zawsze błędny walidator z komunikatem.

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

Twierdzę, że logika, którą próbujesz wykonać, nie należy do takiego poziomu w twojej architekturze. Pozwól, aby baza danych wymuszała ograniczenia, takie jak klucze obce itd., A twoja logika biznesowa powinna znajdować się powyżej. Na przykład w twoim encji, którą chcesz zweryfikować, możesz dodać metodę, która zawiera logikę, którą i tak umieścisz w swoich walidatorach.Następnie wystarczy korzystać z nowych metod:

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

zgadzam się z tym stwierdzeniem, ja też uwierzyć, że logika biznesowa nie powinna być połączona z Entity Framework – Eldho

+1

To dyskusyjne. Być może obiekt warstwy domeny może mieć sprawdzanie poprawności. Tak długo jak okropna "warstwa repozytorium przed wzorem EF" nie jest używana ... – James

+0

Zgadzam się, ale dane dynamiczne nie dają wielu opcji sprawdzania poprawności. Ale problemu nie ma, problem polega na tym, że wyjątek DbValidationException nie jest przechwytywany przez DynamicValidator (chociaż dokumenty i artykuły, które znajduję, mówią, że powinien), więc dostaję żółty ekran. W tej chwili nawet nie próbuję mieć dobrej architektury, po prostu mieć coś, co działa :( –

3

Jednym ze sposobów, w jaki sposób achive to może być wdrożenie IDataErrorInfo interfejs na swoich jednostkach tak:

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 
} 

Aby uzyskać dostęp do aktualnego DBContext z metod IDataErrorInfo można użyć this answer. następnie zastąpić SaveChanges metodę context za:

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

Zobacz również this answer aby to działało z DataAnnotations.

Napisałeś:

Jeśli rzucę DbEntityValidationException (lub ValidationException jak sugerowano w tym artykule), ASPNET poradzić jak każdy wyjątek (żółtego ekranu).

Zobacz this answer. Gdy zadzwonisz pod numer SaveChanges, musisz złapać DbEntityValidationException (lub ValidationException), jeśli nie złapiesz ich, aby przetworzyć je w kontrolerze, są one przetwarzane przez domyślną procedurę obsługi błędów.

Albo można użyć DynamicValidator kontrolę złapać ValidationExceptions:

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

Problem z DynamicValidator jest to, że wymaga ControlToValidate własność i łapie tylko wyjątki pochodzących z tej kontroli. Również wyjątki zawarte w innych wyjątkach mogą powodować problemy. Istnieje obejście tego problemu - możesz dziedziczyć po DynamicValidator i zastąpić jego metodę ValidateExceptionsee this blog.

Zobacz this article.

+0

Tak, dokładnie to, co znalazłem, ale DynamicValidator nie łapie wyjątku, nie wiem dlaczego. I debugowania, widzę, że wkracza w metodzie ValidateException i wydaje się, aby go wykryć i robić rzeczy z nim ([kod źródłowy] (http://referencesource.microsoft.com/#System.Web.DynamicData/DynamicData/DynamicValidator. cs, a9f61764351be893, reference)), ale wyjątek nadal idzie do domyślnego programu obsługi błędów: Próbowałem nawet ImprovedDynamicValidator z pakietu Dynamic Data Futures, ale to też nie działa Nie mogę go złapać w Kontroler, ponieważ nie ma go w Dynamic Data –

+0

Widzę, interesujący problem, przyjrzę się temu w czwartek, jeśli nie otrzymam odpowiedzi w międzyczasie. –