Filter alle Navigations-Eigenschaften, bevor Sie geladen werden (lazy oder eager) in den Speicher

Für zukünftige Besucher: für EF6 sind Sie wahrscheinlich besser dran, mit Filter, zum Beispiel über das Projekt: https://github.com/jbogard/EntityFramework.Filters

In der Anwendung, die wir bauen, wir wenden die "soft-löschen" - Muster, bei dem jede Klasse hat eine 'Gelöscht' bool. In der Praxis, jede Klasse erbt einfach von dieser Basisklasse:

public abstract class Entity
{
    public virtual int Id { get; set; }

    public virtual bool Deleted { get; set; }
}

Geben Sie ein kurzes Beispiel, angenommen ich habe die Klassen GymMember und Workout:

public class GymMember: Entity
{
    public string Name { get; set; }

    public virtual ICollection<Workout> Workouts { get; set; }
}

public class Workout: Entity
{
    public virtual DateTime Date { get; set; }
}

Wenn ich hol die Liste der Fitness-Studio-Mitglieder aus der Datenbank, ich kann sicherstellen, dass keiner der 'gelöscht' Fitness-Studio-Mitgliedern abgerufen werden, wie hier:

var gymMembers = context.GymMembers.Where(g => !g.Deleted);

Wenn ich allerdings Durchlaufen diese Fitness-Studio-Mitglieder, Ihre Workouts werden aus der Datenbank geladen, ohne jede Rücksicht für Ihre Deleted Flagge. Zwar kann ich die Schuld Entity Framework nicht Kommissionierung bis auf diese, ich möchte zu konfigurieren oder abfangen lazy-Eigenschaft laden irgendwie so, dass gelöschte Navigations-Eigenschaften sind noch nie geladen.

Ich habe gehen durch, meine Optionen, aber Sie scheinen rar:

Dies ist einfach keine option, da wäre es zu viel manuelle Arbeit. (Unsere Anwendung ist riesig und immer grösser jeden Tag). Wir wollen auch nicht zu geben, die Vorteile der Verwendung von Code First (von denen gibt es viele)

Wieder, keine option. Diese Konfiguration ist nur verfügbar, pro Person. Immer eifrig laden Einrichtungen würde auch zu verhängen eine schwerwiegende Strafe.

  • Anwendung des Ausdrucks Besucher Muster, das automatisch injiziert .Where(e => !e.Deleted) überall, es findet eine IQueryable<Entity> wie beschrieben hier und hier.

Ich tatsächlich getestet, die in einer proof-of-concept-Anwendung, und es klappte wunderbar.
Dies war eine sehr interessante option, aber leider, es nicht zu gelten-Filterung verzögert geladen Navigations-Eigenschaften. Dies ist offensichtlich, wie diejenigen, die faul Eigenschaften erscheinen nicht im Ausdruck/Abfrage und als solche kann nicht ersetzt werden. Ich Frage mich, ob Entity Framework erlauben würde, für eine Injektion Punkt irgendwo in Ihrer DynamicProxy Klasse, lädt der lazy-Eigenschaften.
Ich habe auch Angst für die anderen Folgen, wie die Möglichkeit der Zerschlagung der Include Mechanismus in EF.

  • Schreiben Sie eine benutzerdefinierte Klasse, die ICollection implementiert, sondern filtert die Deleted Entitäten automatisch.

War dies tatsächlich mein Erster Ansatz. Die Idee wäre die Verwendung von background-Eigenschaft für jede Sammlung-Eigenschaft, die intern verwendet eine benutzerdefinierte Auflistungsklasse:

public class GymMember: Entity
{
    public string Name { get; set; }

    private ICollection<Workout> _workouts;
    public virtual ICollection<Workout> Workouts 
    { 
        get { return _workouts ?? (_workouts = new CustomCollection()); }
        set { _workouts = new CustomCollection(value); }
     }

}

Dieser Ansatz ist eigentlich nicht schlecht, ich habe noch einige Probleme mit ihm:

  • Es dennoch lädt alle Workouts in den Speicher und Filter, die Deleted diejenigen, wenn die Eigenschaft setter ist der hit. Meiner bescheidenen Meinung nach ist dies viel zu spät.

  • Es ist eine logische Diskrepanz zwischen durchgeführten Abfragen und die Daten, die geladen wird.

Bild ein Szenario, wo ich möchte eine Liste der Fitness-Studio-Mitglieder, haben Sie ein workout-seit letzter Woche:

var gymMembers = context.GymMembers.Where(g => g.Workouts.Any(w => w.Date >= DateTime.Now.AddDays(-7).Date));

Diese Abfrage zurückgeben kann, eine Fitness-Studio-Mitglied, dass nur Trainingseinheiten, die gelöscht werden, sondern auch das Prädikat erfüllen. Sind Sie einmal in den Speicher geladen, es scheint, als wenn das Fitness-Studio Mitglied hat keine workouts überhaupt!
Man könnte sagen, die Entwickler sollten sich bewusst sein, der Deleted und stets in seinem Abfragen, aber das ist etwas, das würde ich wirklich gerne vermeiden. Vielleicht die ExpressionVisitor anbieten könnte, hier die Antwort wieder.

  • Es ist eigentlich unmöglich, daneben eine navigation, die Eigenschaft als Deleted bei der Verwendung der customcollection hinzuzufügen.

Stellen Sie sich dieses Szenario:

var gymMember = context.GymMembers.First();
gymMember.Workouts.First().Deleted = true;
context.SaveChanges();`

Würden Sie erwarten, dass die entsprechenden Workout Datensatz in der Datenbank aktualisiert, und Sie würden falsch sein! Da die gymMember wird geprüft, indem die ChangeTracker für alle änderungen, die Eigenschaft gymMember.Workouts plötzlich zurück 1 weniger Training. Das ist, weil customcollection hinzuzufügen filtert automatisch gelöscht Instanzen, erinnern Sie sich? So, jetzt Entity Framework denkt, dass das Training muss gelöscht werden, und EF wird versuchen, die FK auf null gesetzt wird, oder tatsächlich löschen Sie den Datensatz. (je nachdem, wie deine DB konfiguriert ist). Dies ist, was wir versuchen zu vermeiden, mit den soft-löschen-Muster zu beginnen!!!

Stieß ich auf ein interessanter blog post, der überschreibt die Standard - SaveChanges Methode der DbContext so, dass alle Einträge mit einem EntityState.Deleted sind geändert zurück zu EntityState.Modified aber das wieder, fühlt sich "hacky" und eher unsicher. Allerdings bin ich bereit, es auszuprobieren, wenn es löst die Probleme, ohne irgendwelche unbeabsichtigten Nebenwirkungen.


Also hier bin ich StackOverflow. Ich hab recherchiert, meine Optionen sehr ausführlich, wenn ich so sagen darf mich, und ich bin mit meinem Latein am Ende. So, jetzt Wende ich mich an Euch. Wie haben Sie die umgesetzt weichen löscht in Ihrem Unternehmen Anwendung?

Wiederholen, dies sind die Anforderungen, die ich bin auf der Suche nach:

  • Abfragen sollten automatisch ausschließen, die Deleted Personen auf der DB-Ebene
  • Löschen einer Entität und der Aufruf 'SaveChanges' sollten einfach aktualisieren Sie den entsprechenden Datensatz und haben keine weiteren Nebenwirkungen.
  • Wenn die Navigations-Eigenschaften geladen werden, egal ob lazy oder eager, der Deleted sollten diejenigen werden automatisch ausgeschlossen.

Ich freue mich über alle Vorschläge, danke im Voraus.

  • Haben Sie versucht, Sie anzurufen .ToList() für das erste laden zu zwingen, EF, um in den Speicher laden?
  • Ich fürchte, Ihr Kommentar macht nicht viel Sinn. Hast du wirklich gelesen, meine ganze Frage in unter 1 minute? Das ist beeindruckend!
  • Danke für den Sarkasmus, wenn jemand versucht, Ihnen zu helfen.
  • Meine Entschuldigung, ich meine nicht, Sie zu beleidigen. Aufruf von ToList auf dem Fitness-Studio-Mitglieder wäre in der Tat laden Sie die Fitness-Studio-Mitglieder in den Speicher, aber ich sehe wirklich nicht, wie, dass würde mein problem lösen?
  • Ich denke, Sie müssen zurück zu den Grundlagen. Was Sie erklärt, ist nicht meine Erfahrung mit EF. "Aber, wenn ich Durchlaufen diese Fitness-Studio-Mitglieder, Ihre Trainingseinheiten werden aus der Datenbank geladen, ohne Rücksicht auf Ihr Gelöscht-flag"...... Es ist etwas falsch hier. Es MUß NICHT auch diese Aufzeichnungen. Überprüfen Sie Ihr Prädikat. 2. Deaktivieren LAZY Loading in Ihrem Kontext. Sobald Sie das haben, sortiert, explizit laden, und das Training für jedes Fitness-Mitglied in einer for-Schleife. Gebrauch, den er IQueryable zurück geben.
  • Nun, natürlich muss es nicht enthalten die Datensätze, das ist, was ich versuche zu erreichen! Meine Frage ist: wie? Auch: deaktivieren der lazy loading an dieser Stelle, das ist nicht wirklich eine option, da unsere Anwendung bereits verwendet es königlich überall. Ich will auch nicht aufgeben, die Vorteile von lazy loading.
  • Weich Löschen ist viel schwieriger als es scheinen mag auf den ersten Blick, EF oder nicht. Ich schlage vor, Sie sollten betrachten Sie andere Muster wie Archivierung zum Beispiel. Finden Sie diese stackoverflow.com/questions/9880623/soft-delete-vs-db-archive und auch das ayende.com/blog/4157/avoid-soft-deletes (es ist auf Nhibernate, aber die Idee ist die gleiche).
  • Ich fürchte, die Entscheidung zur Nutzung der soft-löschen-Muster war nicht meins zu machen. Ich bin berufen zu lösen alle Ihre Probleme, obwohl. 🙂

InformationsquelleAutor Moeri | 2013-09-04
Schreibe einen Kommentar