Kaskadieren von "gelöschten" Datensätzen, die nicht wirklich gelöscht wurden

8

Ich versuche nur, ein paar Ideen zu bekommen, was die Leute für dieses Szenario tun. Wir haben eine Systemdatenbank (SQL Server 2008 R2) mit Tabellen und jede Tabelle hat ein Feld, das wir "Gelöscht" nennen können. Es ist im Grunde ein Bitfeld, wenn es eine 1 ist, wird der Datensatz gelöscht, wenn es eine 0 ist, wird es nicht gelöscht. Das Feld ist nicht nullbar und seine Standardeinstellung ist natürlich 0.

Wir können keine echten Löschungen in der Datenbank zulassen. Um dies zu umgehen, setzen wir ein Bitfeld (Gelöscht) auf true. In unserer Anwendung erhalten wir Fragen, die folgendermaßen aussehen:

SELECT blah FROM MyTable WHERE .. AND Deleted=0

Grundsätzlich filtern wir nach Datensätzen, sodass wir nur nicht gelöschte Zeilen erhalten. Unser Problem sind verwandte Datensätze, die kaskadiert werden müssen. Was bevorzugen die Leute, sollten wir dies im serverseitigen Code tun, damit beim Löschen eines Datensatzes alle zugehörigen Datensätze gelöscht werden (setzt das gelöschte Bitfeld auf true)? Oder sollte dies ein Trigger sein, der dieses Feld überprüfen und das Bitfeld für alle zugehörigen Datensätze auf 1 setzen muss?

Oder sind wir völlig auf dem falschen Weg?

JonH
quelle
Verwenden Sie eine Ansicht, die so gelöscht wurde, dass sie niemals ins Bild kommt, und gruppieren Sie sich auf diesem Bitfeld
Ratschenfreak am
@ratchetfreak - das hilft nicht bei den zugehörigen Datensätzen ... wie gehst du mit der Kaskade des Löschens um? Stellen Sie sich eine Unternehmensseite mit zugehörigen Problemen vor. Wenn jemand das Unternehmen löscht (setzt Company.Deleted = 1), wie löschen Sie die mit diesem Unternehmen verbundenen Probleme?
JonH
2
Das einzige, was es automatisieren würde, ist ein Update-Trigger
Ratschenfreak
1
@ratchetfreak - Das ist meine Frage, sollten wir sie über einen Update-Trigger oder über den serverseitigen Code behandeln und warum. Ich kenne die Antwort darauf irgendwie. Ich hatte nur gehofft, eine Vorstellung davon zu bekommen, was andere für das weiche Löschen tun - wie würden Sie die Beziehungen sanft löschen (Kaskadenlöschen haben Sie, ohne es wirklich zu löschen).
JonH
2
Warum müssen Sie verwandte Daten löschen? Wenn auf das übergeordnete Element der zugehörigen Daten nicht zugegriffen werden kann, wie werden Sie darauf zugreifen?
Kevin

Antworten:

2

Hier gibt es keine gute Lösung. Datenbanken bieten eine spezielle, effiziente kaskadierte Löschung über Fremdschlüssel. Wenn jedoch, wie Sie sagen, die tatsächliche Löschung keine Option ist, können Sie diese native Kaskadierung nicht nutzen.

Abhängig davon, ob Löschvorgänge häufig oder selten vorkommen, ist es effizienter, die Kaskadierung sofort (über zusätzliche Abfragen oder Trigger) zu emulieren, wenn Sie etwas pseudo-löschen, oder einfach immer alles aus der Datenbank abzurufen und nach dem Löschen zu filtern Flag in der Geschäftslogik.

Persönlich habe ich immer eine dritte Option verwendet: Auf alle Nebendatensätze kann nur über den Stammdatensatz zugegriffen werden. Dies geschieht nie, wenn dieser Datensatz sanft gelöscht wird. Sie müssen also nichts tun! Dies funktioniert natürlich nur, wenn Ihr Datenmodell ein strenger Baum ist (Kommentare werden nur beim Anzeigen des Produkts abgerufen, für das sie gelten, Benutzerrechte werden nur beim Verwalten des Benutzers abgerufen, zu dem sie gehören usw.) und nicht in einem Web (in dem Sie möglicherweise Fragen stellen alle Kommentare oder alle Berechtigungsdatensätze gleichgültig), aber ich finde, dass dies für überraschend viele Szenarien funktionieren kann.

Kilian Foth
quelle
@ Killian - Ich glaube, dies ist möglicherweise der Weg, den wir einschlagen müssen (Auslöser). Als Team müssen wir dies jedoch mehr mit den Stakeholdern darüber diskutieren, was kaskadieren sollte oder nicht. Vielen Dank für Ihre tolle Eingabe.
JonH
5

Ich habe dies bereits mit Audit-Tabellen gemacht, bei denen jede Änderung an einer Datenbank in eine Audit-Spiegeltabelle (Einfügen / Aktualisieren / Löschen) geschrieben wird und die tatsächlichen realen Elemente kaskadiert gelöscht werden.

Die Spiegeltabellen sind mit der realen Tabelle identisch, wobei 3 Spalten hinzugefügt werden: "ChangeType", "User", "Date".

Dies hat den doppelten Vorteil, dass Daten korrekt gelöscht werden können, aber auch der Status der Datenbank zu jedem Zeitpunkt neu erstellt und der gesamte Verlauf eines Elements dokumentiert werden kann.

Ich füge hinzu, dass ich für das Kaskadieren von Löschvorgängen im Allgemeinen das Kaskadieren von Löschvorgängen auf dem Client bevorzuge. Der Server sollte nicht versuchen, diesbezüglich zu klug zu sein. Wenn ein Benutzer ein Unternehmen löscht und damit verbundene Probleme vorliegen, sollte die Aktion "Unternehmen löschen" ebenfalls gelöscht werden entsprechende Datensätze.

Dies war für ein Finanzmanagementsystem für eine große Investmentbank, daher war die Überprüfbarkeit ein kritisches Merkmal.

Michael
quelle
Ich kann dies als einen Weg sehen und wir haben darüber nachgedacht, aber ich glaube, es passt zu Finanzsystemen. Wir müssten so viele weitere Tabellen und Beziehungen duplizieren, und die Codebasis würde erheblich wachsen. Ich kann jedoch die Notwendigkeit in Ihrem Fall erkennen.
JonH
Das Duplizieren der Tabellen ist kein Problem, wenn die Überwachungstabellen automatisch bereitgestellt und synchron gehalten werden. Wie beim Code mussten wir lediglich einen Injektor auf der Datenebene bereitstellen, um zwischen den Überwachungstabellen und den Live-Tabellen zu wechseln - alle Abfragen gleich geblieben.
Michael
Michael, wenn es dir nichts ausmacht, wenn ich frage, wie groß dein Entwicklerteam für ein solches Projekt war?
JonH
Es ist eine Weile her, also bin ich mir nicht 100% sicher, aber ich denke 4 Entwickler, 3 Tester und 1 Analyst.
Michael
1

Tun Sie dies explizit für die Anweisung delete / undelete. Es gibt wahrscheinlich auch mehrere Szenarien, in denen Sie das Löschen nicht kaskadieren möchten.

> Update table1 set deleted=@flag where...
> Update table2 set deleted=@flag where...

Zum Beispiel; Betrachten Sie eine Person mit mehreren Adressen.

Löschen Sie die Person, setzen Sie einfach das Lösch-Flag auf die Person. Das Löschen muss nicht an Adressen kaskadiert werden, da wir diese Adressen bei der Wiederherstellung zurückhaben möchten.

Angenommen, die Person ist umgezogen, dann möchten wir das Löschflag nur für die alte Adresse aktualisieren und die anderen Adressen und die Person in Ruhe lassen. Eine Kaskadierung ist daher möglicherweise nicht immer erforderlich und hängt vom Szenario ab.

Ich denke, Sie müssen explizit sein, je nachdem, wie Ihr Modell eingerichtet ist und was Sie löschen.

Jon Raynor
quelle
1
Sollte die Integrität nicht von der Datenbank (mit einem Auslöser) aufrechterhalten werden, anstatt zu erwarten, dass der Anwendungsprogrammierer alle Beziehungen zwischen den Tabellen kennt und was wo kaskadiert werden muss?
@MichealIT - Hier gibt es keine Datenintegrität, da lediglich eine Spalte aktualisiert wird. Sie haben Recht, dass das Update in einen Trigger gehen könnte, aber eine explizite Definition mit einem Löschvorgang (SP) würde das Auffinden erleichtern. Im Trigger müsste man das Delete-Flag abfragen und geeignete Maßnahmen ergreifen, um festzustellen, ob es sich um eine 1 oder 0 handelt. Die Trigger-Logik ist im Gegensatz zu einer gespeicherten Prozedur tendenziell dunkler.
Jon Raynor
@MichealT - In diesem Beispiel lassen Sie den Adressdatensatz in Ruhe, es sei denn, er sollte "gelöscht" werden. Im Sinne einer relationalen Datenbank behalten Sie weiterhin die relationale Integrität bei, da alle diese Datensätze noch vorhanden sind. Es sind die Geschäftsregeln, die sie ausschließen. Und ja, ein Entwickler versteht besser, wie all diese weichen Löschvorgänge behandelt werden.
JeffO