2016-04-28 7 views
12

Ich bin auf der Suche nach einer Lösung, um einige benutzerdefinierte Entität Validierung (die Datenbankzugriff, Cross-Member-Validierung erfordern würde), wenn der Benutzer seine Änderungen in einem dynamischen Daten Bildschirm speichert, mit Entity Framework.
Die Validierung ist komplexer als das, was ich mit den Attributen tun (es einen Zugriff auf die Datenbank benötigt, etc.)Benutzerdefinierte erweiterte Entität Validierung mit dynamischen Daten

Können Sie die Savechanges aufrufen abfangen?
Ich habe versucht, ValidateEntity im DbContext-Objekt zu überschreiben, aber Dynamic Data scheint es nicht zu nennen (wahrscheinlich weil es den internen ObjectContext verwendet, nicht sicher warum), und das Überschreiben von SaveChanges hilft auch nicht.
Ich habe keine Veranstaltung sehen, dass ich abonnieren könnte ...

Die documentation soll helfen:

anpassen Validierung für ein einzelnes Datenfeld durch Überschreiben der OnValidate Methode oder die Handhabung des Validate-Ereignisses , die aufgerufen werden, wenn ein Datenfeld geändert wird. Mit diesem Ansatz können Sie die Validierung und Geschäftslogik für ein einzelnes Feld hinzufügen. Dieser Ansatz ist eher als das Hinzufügen der Validierung für ein einzelnes Feld. Es ist nützlich , wenn dieselbe Validierungslogik auf mehr als ein Datenfeld angewendet werden kann. Sie können auch Validierungsprüfungen durchführen, bei denen mehrere Felder enthalten.

Aber ich bin mit POCO Entity Framework 6 Klassen so gibt es keine OnValidate Methode außer Kraft zu setzen, und von dem, was ich lese dies für LinqToSql ist, und ich kann das Validate Ereignis nicht finden sie erwähnen.

Ich habe versucht, das SavingChanges Ereignis der inneren ObjectContext im Konstruktor meines DbContext zu abonnieren, die ValidateEntity manuell zu nennen, aber ich weiß nicht, was mit dem Ergebnis zu tun. Wenn ich eine DbEntityValidationException (oder eine ValidationException wie in this article vorgeschlagen) werfen, behandeln ASPNET es wie jede Ausnahme (gelber Bildschirm).

Die Implementierung IValidatableObject funktioniert auch nicht.

Ich habe auch versucht, meine eigene DynamicValidator zu sehen, was passiert, aber ohne Erfolg, scheint es die Ausnahme zu behandeln (wenn ich ValidateException überschreiben, und einen Haltepunkt setzen, sehe ich es) aber es ist immer noch bis zum Standard sprudeln Fehlerhandler und zeigt einen gelben Bildschirm an. Ich muss etwas verpassen.

Also, wie sollten Sie komplexe Validierung (Querfeld, mit Abfragen usw.) auf Entitäten vor dem Speichern in Dynamic Data/EF durchführen?

Antwort

0

fand ich eine Abhilfe Ich mag es nicht, aber es funktioniert:

Mein Kontext noch die Validierung durchführt und ein ValidationException bei Bedarf wirft.

Als ListView scheint nicht die Ausnahme zu fangen und zu handhaben, kann ich es mir durch den Umgang mit den OnItemUpdated oder OnItemInserted Ereignis des 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 verwendet wird, um die Ausnahmemeldung an die hinzufügen Validierungszusammenfassung. Es fügt einen "falschen", immer fehlgeschlagenen Validierer mit der Nachricht hinzu.

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

Ich würde argumentieren, dass Logik, wie Sie versuchen, durchzuführen, nicht auf einer solchen Ebene in Ihrer Architektur gehört. Lassen Sie die Datenbank die Einschränkungen erzwingen, die sie haben soll, wie Fremdschlüssel usw., und haben Sie Ihre Geschäftslogik eine Schicht darüber. In Ihrer Entität, die Sie validieren möchten, könnten Sie beispielsweise eine IsValidForAddOrUpdate() Methode hinzufügen, die die Logik enthält, die Sie ohnehin in Ihre Validatoren eingegeben haben.Dann nutzen Sie einfach die neuen Methoden:

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

i mit dieser Aussage zustimmen, ich glaube auch, dass die Geschäftslogik nicht mit Entity Framework gekoppelt werden soll – Eldho

+1

Es diskutierbar ist. Möglicherweise könnte ein Domain-Layer-Objekt stattdessen die Validierung haben. Solange das schreckliche Repository-Layer vor dem EF-Muster nicht verwendet wird ... – James

+0

stimme ich zu, aber dynamische Daten gibt nicht viele Optionen für die Validierung. Aber das Problem ist nicht da, das Problem ist, dass DbValidationException nicht von DynamicValidator abgefangen wird (obwohl die Dokumente und Artikel, die ich finde, es sagen sollte), so bekomme ich einen gelben Bildschirm. Im Moment versuche ich nicht einmal, eine gute Architektur zu haben, nur um etwas zu haben, das funktioniert :(. –

3

Eine Möglichkeit, wie dies achive könnte so IDataErrorInfo Schnittstelle auf Ihre Entitäten implementieren:

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 
} 

Für den Zugriff auf aktuelle DbContext von IDataErrorInfo Methoden, die Sie this answer verwenden können. Dann Ihren Context Savechanges-Methode außer Kraft setzen:

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

Siehe auch this answer, um es mit DataAnnotations zu arbeiten.

Sie schrieb:

Wenn ich ein DbEntityValidationException (oder ein Validation wie in diesem Artikel vorgeschlagen) werfen, ASPNET sie wie jede Ausnahme (gelb-Bildschirm) behandeln.

Siehe this answer. Wenn Sie SaveChanges aufrufen, müssen Sie DbEntityValidationException (oder ValidationException) fangen, wenn Sie sie nicht abfangen, um sie in Ihrem Controller zu verarbeiten, werden sie von der Standardfehlerbehandlungsroutine verarbeitet.

Oder können Sie DynamicValidator Steuerung verwenden ValidationExceptions zu fangen:

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

Das Problem mit DynamicValidator ist, dass es ControlToValidate Eigenschaft erfordert und es fängt nur Ausnahmen von dieser Kontrolle kommen. Auch Ausnahmen, die in anderen Ausnahmen eingeschlossen sind, können Probleme verursachen. Es gibt eine Problemumgehung - Sie können von DynamicValidator erben und seine ValidateException Methode see this blog überschreiben.

Siehe this article.

+0

Ja, genau das, was ich gefunden habe, aber der DynamicValidator fängt die Ausnahme nicht, ich weiß nicht warum Ich debugge, ich sehe, dass es in die ValidateException-Methode tritt und es scheint, es zu entdecken und Dinge damit zu tun ([Quellcode] (http://referencesource.microsoft.com/#System.Web.DynamicData/DynamicData/DynamicValidator. cs, a9f61764351be893, Verweise)), aber die Exception geht immer noch bis zum Standard - Error - Handler über: Ich habe sogar den ImprovedDynamicValidator aus dem Dynamic Data Futures Paket ausprobiert, aber es funktioniert auch nicht .. Ich kann es nicht in der Controller, da es keine mit Dynamic Data gibt –

+0

Ich sehe, interessantes Problem, ich werde es am Donnerstag anschauen, wenn es zwischenzeitlich nicht beantwortet wird. –