Frage

Ich habe einen Prozess, der ein Excel-Spreadhseet importiert und die Daten in meine Datenobjekte analysiert.Die Quelle dieser Daten ist sehr fraglich, da wir unseren Kunden von einem tabellenbasierten Datenmanagement auf ein verwaltetes Datenbanksystem mit Prüfungen auf gültige Daten umstellen.

Während meines Importvorgangs führe ich einige grundlegende Plausibilitätsprüfungen der Daten durch, um festzustellen, wie schlecht die Daten sein könnten, die wir importieren, aber meine Gesamtvalidierung erfolgt im DbContext.

Ein Teil dessen, was ich versuche, besteht darin, dass ich in der Tabelle die Zeilennummer angeben möchte, in der angegeben wird, dass die Daten fehlerhaft sind, damit sie leicht feststellen können, was repariert werden muss, damit die Datei importiert werden kann.

Sobald ich die Daten aus der Tabelle habe (model) und die Opportunity, mit der sie aus der Datenbank arbeiten (opp), hier ist der Pseudocode meines Prozesses:

foreach (var model in Spreadsheet.Rows) { // Again, pseudocode
    if(opp != null && ValidateModel(model, opp, row)) {
        // Copy properties to the database object

        // This is in a Repository-layer method, not directly in my import process.
        // Just written here for clarity instead of several nested method calls.
        context.SaveChanges(); 
    }
}

Bei Bedarf kann ich hier mehr Code bereitstellen, aber das Problem liegt in meinem DbContext ValidateEntity() Methode (Überschreibung von DbContext).

Auch hier ist an dem Code, den ich geschrieben habe, meines Wissens nichts auszusetzen, aber wenn eine Opportunity diese Validierungsstufe nicht bestanden hat, bleibt sie als Teil der nicht gespeicherten Objekte in der context, was bedeutet, dass es jedes Mal wiederholt versucht, validiert zu werden ValidateEntity() wird genannt.Dies führt dazu, dass dieselbe Validierungsfehlermeldung für jede Zeile wiederholt wird, nachdem das anfängliche Problem aufgetreten ist.

Gibt es eine Möglichkeit, [bearbeiten]Holen Sie sich den Kontext, um den Versuch, das Objekt zu validieren, zu beenden, nachdem die Validierung einmal fehlgeschlagen ist[bearbeiten]?Ich weiß, ich könnte bis zum Ende warten und anrufen context.SaveChanges() einmal am Ende, um dies zu umgehen, aber ich würde dies gerne mit der Zeile in der Datenbank abgleichen können, in der es sich befindet.

Als Referenz verwende ich Entity Framework 6.1 mit einem Code First-Ansatz.

BEARBEITEN Ich versuche, Marc L. weiter zu klären.(einschließlich einer Aktualisierung des obigen Codeblocks)

Im Moment durchläuft mein Prozess so viele Zeilen, wie in der Tabelle vorhanden sind.Der Grund, warum ich meine Repository-Ebene mit jedem zu speichernden Objekt aufrufe, anstatt mit einem Ansatz zu arbeiten, der nur Aufrufe vornimmt context.SaveChanges() Einmal besteht darin, mir die Möglichkeit zu geben, festzustellen, welche Zeile einen Validierungsfehler verursacht.

Ich bin froh, dass mein DbContext Brauch ist ValidateEntity() Methoden fangen die Validierungsfehler ab, aber das Problem liegt darin, dass sie keine Fehler auslösen DbEntityValidationException für dieselbe Entität mehrmals.

Ich möchte, dass der Kontext nicht mehr versucht, das Objekt zu speichern, egal wie oft, wenn die Validierung des Objekts einmal fehlschlägt context.SaveChanges() wird genannt.

War es hilfreich?

Lösung

Ihre Frage ist kein Betrug (hier geht es um das Speichern, nicht um das Laden von Entitäten), aber Sie könnten Jimmys oben genannten Ratschlägen folgen.Das heißt, sobald eine Entität zum Kontext hinzugefügt wird, wird sie im Status „hinzugefügt“ verfolgt und die einzige Möglichkeit, eine erneute Validierung zu verhindern, besteht darin, sie zu trennen.Es handelt sich um einen SO-internen Link, aber ich reproduziere den Codeausschnitt:

dbContext.Entry(entity).State = EntityState.Detached;

Ich glaube jedoch nicht, dass Sie diesen Weg einschlagen möchten, da Sie Ausnahmen verwenden, um den Status unnötig zu verwalten (Ausnahmen sind bekanntermaßen teuer).

Ausgehend von den gegebenen Informationen würde ich eine eher satzbasierte Lösung verwenden:

  • Ändern Sie Ihre Modellklasse so, dass sie eine RowID enthält, die die ursprüngliche Tabellenzeile aufzeichnet (es gibt wahrscheinlich auch andere gute Gründe dafür).
  • Deaktivieren Sie die Entitätsverfolgung für den Kontext (Wechsel der Änderungserkennung ermöglichen dies jeweils Add() sein O(1))
  • Fügen Sie alle Entitäten hinzu
  • Anruf context.GetValidationErrors() und erhalten Sie alle Ihre Fehler auf einmal, indem Sie die oben genannte RowID verwenden, um die ungültigen Zeilen zu identifizieren.

Sie haben nicht angegeben, ob Ihr Prozess die guten Zeilen speichern oder die Datei als Ganzes ablehnen soll, aber dies wird beidem entgegenkommen – das heißt, wenn Sie die guten Zeilen speichern müssen, trennen Sie alle ungültigen Zeilen mit dem Code oben und Dann SaveChanges().


Wenn Sie schließlich die guten Zeilen speichern möchten und mit der satzbasierten Methode nicht zufrieden sind, ist es besser, eine neue zu verwenden DbContext für jede einzelne Zeile, oder erstellen Sie zumindest eine neue DbContext nach jedem Fehler.Das ADO.NET-Team besteht darauf, dass die Kontexterstellung „relativ günstig“ ist (leider habe ich hierfür weder ein Zitat noch Statistiken zur Hand), sodass dies Ihren Durchsatz nicht zu sehr beeinträchtigen sollte.Trotzdem bleibt es zumindest O(n).Ich würde es Ihnen nicht verübeln, denn die Verwaltung eines großen Kontexts kann Sie auch für andere Probleme öffnen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top