Gibt es Beispiele für nicht-CRUD-Ansätze?


14

Ich bin Programmierer, habe aber auch als Archivar gearbeitet. Als Archivar geht es viel darum, Daten zu speichern.

Ich bin oft mit Kollegen in Streit geraten, wenn es um Operationen mit Daten geht. Ich mag das U und das D in CRUD nicht so sehr. Statt einen Datensatz zu aktualisieren, ziehe ich es vor, einen neuen hinzuzufügen und einen Verweis auf den alten Datensatz zu haben. Auf diese Weise erstellen Sie eine Änderungshistorie. Ich mag es auch nicht, Datensätze zu löschen, sondern sie als inaktiv zu markieren.

Gibt es dafür einen Begriff? Grundsätzlich nur Daten erstellen und lesen? Gibt es Beispiele für diesen Ansatz?


1
Is there a term for this? Basically only creating and reading data?Klar gibt es: CR; P
yannis

7
Aus Sicht des Benutzers ist das immer noch CRUD. Mir sind keine spezifischen Bezeichnungen für diesen Implementierungsstil bekannt, aber ich denke, dass dies in vielen Anwendungen üblich ist. (Stack Exchange ist ein gutes Beispiel ...)
Mark E. Haase

Vielleicht möchten Sie einen Vortrag namens " The Impedance Mismatch is Our Fault" sehen .
Anton Barkovsky

+1 Irgendwann möchte jemand Berichte, und es ist sehr schwierig, Berichte zu Daten zu erstellen, die nicht vorhanden sind, weil sie nicht mehr vorhanden sind. Ich finde Ihren Ansatz sehr vorausschauend.
Chuck Conway

2
Sie können sich auch einen Vortrag über Datomic ansehen: infoq.com/presentations/The-Design-of-Datomic
Marjan Venema

Antworten:


16

Das Markieren eines Datensatzes als gelöscht wird als weiches Löschen bezeichnet . Ich habe noch nie eine alternative Phrase zum Aktualisieren gehört, aber ich schätze, das liegt daran, dass Sie den alten Datensatz vorläufig löschen und einen neuen erstellen.

Es ist anzumerken, dass dies eine umstrittene Technik ist. Siehe Links: Con vs Pro .


11

Eines der Probleme beim Beibehalten eines Änderungsverlaufs besteht darin, dass die Datenbank überfüllt ist und sich ihre Größe (abhängig von den Verwendungsmustern) erheblich erhöhen kann. Daher ist es eine gute Idee, den Audit-Trail an einem separaten Ort zu speichern und die tatsächlichen Anwendungstabellen nur mit relevanten Daten zu füllen. Jedes Mal, wenn eine CRUD-Operation von der Anwendung ausgeführt wird, wird die Änderung in den Prüftabellen aufgezeichnet und die CRUD-Operation wird für die Anwendungstabellen ausgeführt (keine vorläufigen Löschvorgänge).

Indem Sie den Audit-Trail getrennt halten, erhalten Sie einen makellosen Datenspeicher, mit dem Ihre Anwendung interagieren kann, und behalten den Änderungsverlauf bei, falls Sie ihn benötigen. Sie können den Audit-Trail jetzt auch separat archivieren oder sogar zerstören, je nach Ihren Geschäftsanforderungen.


3
Dies. Auch die referentielle Integrität wird zum Albtraum. Sie können keinen Fremdschlüssel für "den einen Datensatz in dieser Tabelle mit diesem nicht eindeutigen Schlüssel, der nicht als gelöscht markiert ist" angeben. Sie können dies umgehen, indem Sie die Daten für die Kopie eines Datensatzes, der aktualisiert werden soll, in einer anderen Tabelle speichern, bevor Sie diese "Arbeitskopie" mit den neuen Daten aktualisieren. Sie müssen sich jedoch noch mit großen Datenmengen befassen.
KeithS

5

EventSourcing klingt nach dem Muster, nach dem Sie suchen.

Nehmen wir ein Beispiel mit einem einfachen "Auto" -Objekt, dessen Farbe wir verfolgen möchten (Pseudo-C # -Code folgt).

public class Car {
  public string Color { get; set; }
  public Car() { this.Color = "Blue"; }
}

Bei einer CRUD-Implementierung würde die vorherige Farbe verloren gehen, wenn wir die Farbe des Autos aktualisieren.

MyCar.Color = "Red";
MyCar.Save();  // Persist the update to the database and lose the previous data

Dieser Informationsverlust scheint mir das zu sein, was Sie am liebsten vermeiden möchten (daher die Abneigung gegen das Aktualisieren und Löschen eines Teils des CRUD-Musters).

Wenn wir die Fahrzeugklasse umschreiben würden, um stattdessen auf Ereignisse zu reagieren, wenn die Änderung aktualisiert wird, könnte dies so aussehen:

public class Car {
    public string Color { get; private set; } // Cannot be set from outside the class

    public void ApplyEvent(CarColorChangedEvent e) {
      this.Color = e.Color;
    }
}

Wie würden wir nun die Farbe dieses Objekts aktualisieren? Wir könnten ein CarColorChanged- Event erstellen !

var evnt = new CarColorChangedEvent("Red");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Bemerken Sie das Fehlen eines Speichers für das tatsächliche Modellobjekt? Das liegt daran, dass wir das Modell nicht direkt beibehalten, sondern die Ereignisse beibehalten, die das Modell in den aktuellen Zustand versetzen. Diese Ereignisse sollten sein unveränderlich sein .

Lassen Sie uns jetzt einen schnellen Vorlauf durchführen und die Farbe noch einige Male ändern:

var evnt = new CarColorChangedEvent("Green");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

var evnt = new CarColorChangedEvent("Purple");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Wenn wir uns unseren Ereignisspeicher ansehen würden (könnte eine Beziehungsdatenbank sein, dateibasiert usw.), würden wir eine Reihe von Ereignissen sehen, die sich auf unser Autoobjekt beziehen:

CarColorChangedEvent => Red
CarColorChangedEvent => Green
CarColorChangedEvent => Purple

Wenn wir dieses Autoobjekt neu erstellen möchten, können wir dies einfach tun, indem wir ein neues Autoobjekt erstellen und die Ereignisse aus unserem Veranstaltungsspeicher auf dieses Objekt anwenden.

var MyCar = new Car();
var events = MyDatabase.SelectEventsForCar("CarIdentifierHere");
foreach(var e in events) {
  MyCar.ApplyEvent(e);
}
Console.WriteLine(MyCar.Color); // Purple

Mit dem Ereignisstrom können wir den Zustand des Autos auf einen früheren Zeitraum zurücksetzen, indem wir einfach ein neues Autoobjekt erstellen und nur die gewünschten Ereignisse anwenden:

var MyCar = new Car();
var event = MyDatabase.GetFirstEventForCar("CarIdentifierHere");
MyCar.ApplyEvent(e);
Console.WriteLine(MyCar.Color); // Red

5

Event Sourcing ist der richtige Weg, und Sie sollten einen Blick darauf werfen, was Greg Young dazu zu sagen hat.

http://goodenoughsoftware.net/

Schauen Sie sich auch diese Präsentation in seiner Datenbank (Event Store) an. Sie können auch andere Videos finden.

http://oredev.org/2012/sessions/a-deep-look-into-the-event-store

Ich würde mich nicht für die "Soft-Deletes" -Antwort entscheiden, es sei denn, Sie müssen in der Lage sein, nach gelöschten Elementen zu suchen, aber dann sollten Sie sie nicht als gelöscht, sondern als archiviert betrachten. Ich denke, Terminologie ist hier sehr wichtig.

Ich würde auch keine "Versionstabelle" führen wollen. Alle "Versionstabellen", die ich je gesehen habe (einschließlich dem auf Ich versuche zur Zeit , um aufzuräumen - 7 Jahre von Daten aufgrund von Fehlern beschädigt ... und keine Möglichkeit , diese wieder zu bekommen , auch wenn wir die historischen Daten haben .. weil das genauso korrupt ist) am Ende aufgrund von Fehlern im Code korrupt sind und am Ende immer noch Daten verloren gehen, weil Sie nie mehr die Daten wiederherstellen können, die durch die Korruption beschädigt wurden.

Beim Event-Sourcing-Modell ist dies nicht der Fall. Sie können immer genau das wiedergeben, was der Benutzer getan hat. Dies ist der sehr wichtige Unterschied zwischen CRUD und Event Sourcing. Die Event Sourcing-Architektur speichert Ereignisse in einem Ereignisspeicher und nicht Datenobjekte oder Domänenmodellobjekte. Ein Ereignis kann sich leicht auf mehrere Objekte auswirken. Stellen Sie sich eine Warenkorblösung vor, bei der Sie jeden Artikel im Warenkorb in eine tatsächliche Bestellung umwandeln. Ein Ereignis wirkt sich auf alle Artikelobjekte sowie auf die Warenkorbobjekte aus, die in ein Bestellobjekt umgewandelt werden.

Wenn Sie eine versionierte Kopie jeder Zeile in jeder Tabelle in der Datenbank aufbewahrt haben, stellen Sie sich den Horror vor, zu einem bestimmten Zeitstempel zurückgespult werden zu müssen, ganz zu schweigen von dem verrückten Speicherplatz- und Leistungsaufwand bei der Verwaltung dieser Versionstabelle.

Mit Event Sourcing können Sie einfach zurückspulen, indem Sie Ereignisse bis zu einem bestimmten Zeitpunkt wiedergeben. Ein schneller Vorlauf kann mithilfe von Snapshots eingerichtet werden, aber das ist alles eine Frage der Implementierung.

Aber der wahre Vorteil, den Sie, da Sie besonders daran interessiert sind, keine Daten zu verlieren, zu schätzen wissen, ist, dass Sie nicht zurückgehen und die Daten bereinigen müssen, wenn Sie einen Fehler im Code entdecken, der diese Daten speichert (was oft unmöglich ist, weil die Daten so gut wie nie vollständig sind). Beheben Sie stattdessen einfach den Fehler und wiederholen Sie alle Ereignisse. Dann haben Sie eine Datenbank mit schönen korrekten Daten.

Wie oft haben Sie den Benutzer beim Debuggen gebeten, Ihnen mitzuteilen, was er getan hat? Warum nicht einfach das wiedergeben, was er getan hat, und dann den Code durchgehen? Ziemlich geschickt, was?

Hoffe das hilft.


2

Nicht gerade Ihr Beispiel, aber in älteren Finanzsystemen hatten Sie WORM- Speicher. Wenn Sie "aktualisieren" mussten, haben Sie einen neuen Datensatz geschrieben, und Sie haben den letzten Datensatz immer als aktuell bezeichnet, aber es konnten niemals festgeschriebene Daten überschrieben werden.

Viele Leute haben diese Idee auf spätere Systeme übertragen. Ich habe gehört, was Sie als WORM-Tabellen bezeichnen, aber nur in diesen Kreisen.


2

Ja, in Unternehmenssystemen gibt es zwei Ansätze:

  • "bi - temporal", bei dem jeder Datensatz einen gültigen Zeitstempel vom und bis zum Zeitpunkt hat (der "aktuelle" Datensatz hat ein gültiges Datum von "forever" - null, "9999-12-31" oder einen so hohen Wert). Datensätze werden niemals gelöscht, stattdessen wird das "Gültig bis" -Datum auf die aktuelle Uhrzeit gesetzt und im Falle einer Aktualisierung wird ein neuer Datensatz mit einem gültigen Datum von der aktuellen Uhrzeit und einem für immer gültigen Datum eingefügt.
  • "Verlaufstabelle" - Jedes Mal, wenn ein Datensatz geändert wird, wird eine Kopie des alten Datensatzes in einer Verlaufs- / Protokolltabelle mit einem Zeitstempel für das Ereignis abgelegt.

Bei beiden Ansätzen gibt es große Unterschiede in der Granularität. Beispiel: Wenn sich die Anzahl der Widgets für einen Bestellartikel ändert, pflegen Sie die Historie für den gesamten Bestellvorgang oder nur für diesen einen Artikel?

Im Allgemeinen ist "bi-temporal" eine Menge zusätzlicher Arbeit und nur dann lohnenswert, wenn Sie viele Anwendungsfälle wie "Prüfer erhält Auftragsstatus zum 31. Dezember" haben.



-2

Grundsätzlich kann Rohöl nicht ohne diese 4 Dinge abgeschlossen werden. Roh bedeutet Erstellen, Lesen, Aktualisieren und Löschen. Wenn Sie also nur versuchen, Daten zu lesen, können Sie dafür eine einfache Abfrage verwenden, aber all diese drei Dinge hängen mit einem und anderen und einfachen Datenbankkonzepten zusammen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.