Der beste Weg, um eine bestellte Liste in der Datenbank zu speichern, während Sie die Bestellung beibehalten


70

Ich habe mich gefragt, ob jemand eine gute Lösung für ein Problem hat, auf das ich in den letzten Jahren mehrfach gestoßen bin.

Ich habe einen Einkaufswagen und mein Kunde fordert ausdrücklich, dass seine Bestellung von Bedeutung ist. Also muss ich die Reihenfolge zur DB beibehalten.

Der naheliegende Weg wäre, einfach ein OrderField einzufügen, in das ich N die Nummer 0 zuweisen und auf diese Weise sortieren würde.

Aber dies würde die Nachbestellung erschweren und ich habe irgendwie das Gefühl, dass diese Lösung irgendwie zerbrechlich ist und eines Tages auf mich zurückkommen wird.

(Ich verwende C # 3,5 mit NHibernate und SQL Server 2005)

Vielen Dank

Antworten:


25

FWIW, ich denke, die Art und Weise, wie Sie vorschlagen (dh die Bestellung in die Datenbank übertragen), ist keine schlechte Lösung für Ihr Problem. Ich denke auch, dass es wahrscheinlich der sicherste / zuverlässigste Weg ist.


1
Ich habe irgendwie das Gefühl, dass die Einhaltung dieser Reihenfolge in Zukunft Kopfschmerzen verursachen kann. Also habe ich gefragt und vielleicht findet jemand eine bessere Lösung.
Tigraine

13
Keine Sorge - es gibt keinen besseren Weg als die Bestellspalte zu verwenden. Was die zukünftigen Kopfschmerzen betrifft ... versuchen Sie nicht, für die Anwendungsfälle zu optimieren, die Sie nicht kennen.
Roland Tepp

1
Da Sie normalerweise den gesamten Einkaufswagen zu Anzeigezwecken abrufen, scheint die Umnummerierung des gesamten
Einkaufswagens

1
Ich stimme zu, es fühlte sich einfach zu zerbrechlich an. Aber nachdem mir klar wurde, dass ich die gesamte Bestelllogik in das Repository stellen kann und das Ganze für meinen Geschäftscode transparent ist, funktioniert es perfekt. Danke für deinen Rat.
Migräne

49

Ok, hier ist meine Lösung, um die Programmierung für alle zu vereinfachen, die mit diesem Thread arbeiten. Der Trick besteht darin, alle Auftragsindizes über oder unter einem Einfügen / Löschen in einem Update zu aktualisieren.

Verwenden einer numerischen Spalte (Ganzzahl) in Ihrer Tabelle, die von den SQL-Abfragen unterstützt wird

CREATE TABLE myitems (Myitem TEXT, id INTEGER PRIMARY KEY, orderindex NUMERIC);

So löschen Sie den Artikel bei orderindex 6:

DELETE FROM myitems WHERE orderindex=6;    
UPDATE myitems SET orderindex = (orderindex - 1) WHERE orderindex > 6;

So tauschen Sie zwei Elemente (4 und 7) aus:

UPDATE myitems SET orderindex = 0 WHERE orderindex = 4;
UPDATE myitems SET orderindex = 4 WHERE orderindex = 7;
UPDATE myitems SET orderindex = 7 WHERE orderindex = 0;

dh 0 wird nicht verwendet, verwenden Sie es also als Dummy, um ein mehrdeutiges Element zu vermeiden.

So fügen Sie bei 3 ein:

 UPDATE myitems SET orderindex = (orderindex + 1) WHERE orderindex > 2;
 INSERT INTO myitems (Myitem,orderindex) values ("MytxtitemHere",3)

31

Die beste Lösung ist eine doppelt verknüpfte Liste . O (1) für alle Operationen außer der Indizierung. Nichts kann SQL schnell indizieren, außer einer where-Klausel für das gewünschte Element.

0,10,20 Typen scheitern. Sequenzspalten schlagen fehl. Die Float-Sequenzspalte schlägt bei Gruppenbewegungen fehl.

Die doppelt verknüpfte Liste ist dieselbe Operation zum Hinzufügen, Entfernen, Löschen von Gruppen, Hinzufügen von Gruppen und Verschieben von Gruppen. Einzelne verknüpfte Liste funktioniert auch in Ordnung. Double Linked ist meiner Meinung nach mit SQL besser. Für eine einzelne verknüpfte Liste muss die gesamte Liste vorhanden sein.


3
Dies ist meiner Meinung nach die beste Lösung. Zum Beispiel habe ich mehr als 300 Filme in meiner Netflix-Warteschlange. Wenn ich ein Element von Position 297 nach oben verschieben würde, müsste Netflix keine 300 Aktualisierungen durchführen. Nur 3 Updates am besten
user35559

6
Was ist der beste Weg, um die ersten 50 Artikel zu erhalten? Muss ich sie einzeln lesen oder gibt es eine magische SQL-Lösung?
Akn

@akn Dies wäre möglich, wenn Sie eine rekursive Abfrage verwenden und dann die Anzahl der Zeilen um 50 begrenzen, um die ersten 50 Zeilen zu erhalten.
Decade Moon

2
Ich verstehe nicht, wie eine doppelt verknüpfte Liste beim "Bestellen" und "Speichern von Bestellsequenzen als float oder int" in der Datenbank hilft. Kommt eine doppelt verknüpfte Listenoperation nicht nur auf der Anwendungsseite vor? Wie aktualisiere ich die Datenbank mit der Liste? Sie müssen noch einen Algorithmus schreiben, um die geordnete Spalte in der Datenbank zu speichern. Es sei denn, ich vermisse etwas.
ANewGuyInTown

1
@ANewGuyInTown Er sagt, implementieren Sie Ihre Zeilendatenstruktur so, als wäre es eine doppelt verknüpfte Liste. Ein Eintrag würde Verweise auf vor und nach Geschwistern in der Listenhierarchie enthalten.
Staaten

10

Wie wäre es mit einer Implementierung einer verknüpften Liste? Mit einer Spalte enthält der Wert (Bestellnummer) des nächsten Artikels. Ich denke, es ist bei weitem am einfachsten zu verwenden, wenn Bestellungen dazwischen eingefügt werden. Keine Umnummerierung erforderlich.


5

Leider gibt es dafür kein Wundermittel. Sie können die Reihenfolge einer SELECTErklärung NICHT OHNE eine Bestellung nach Klausel garantieren . Sie müssen die Spalte hinzufügen und um sie herum programmieren.

Ich weiß nicht, dass ich empfehlen würde, Lücken in der Reihenfolge der Reihenfolge hinzuzufügen. Abhängig von der Größe Ihrer Listen und den Treffern auf der Website können Sie möglicherweise nur sehr wenig für den Overhead-Umgang mit der Logik gewinnen (den Sie noch benötigen würden) für den Anlass, dass alle Lücken aufgebraucht sind). Ich würde genau hinschauen, um zu sehen, welche Vorteile dies für Sie in Ihrer Situation bringen würde.

Entschuldigung, ich kann nichts Besseres anbieten. Ich hoffe, das hat geholfen.


2
Da Sie normalerweise den gesamten Einkaufswagen zu Anzeigezwecken abrufen, scheint die Umnummerierung des gesamten Einkaufswagens kein Problem zu sein.
S.Lott

1
Wenn die Liste so groß ist, dass Sie nicht jede Zeile aktualisieren möchten, wenn Sie etwas neu anordnen, können Sie möglicherweise eine Gleitkomma-DisplayOrder-Spalte verwenden. Ich habe es nicht ausprobiert, aber es ist nur eine Idee ...
Kevin Coulombe

4

Ich würde den Ansatz A, AA, B, BA, BB überhaupt nicht empfehlen. Es ist eine Menge zusätzlicher Verarbeitung erforderlich, um die Hierarchie zu bestimmen, und das Einfügen von Einträgen dazwischen macht überhaupt keinen Spaß.

Fügen Sie einfach ein OrderField hinzu, eine Ganzzahl. Verwenden Sie keine Lücken, da Sie dann entweder mit einem nicht standardmäßigen 'Schritt' bei Ihrer nächsten mittleren Einfügung arbeiten müssen, oder Sie müssen zuerst Ihre Liste neu synchronisieren und dann einen neuen Eintrag hinzufügen.

0 ... N zu haben ist einfach neu zu ordnen. Wenn Sie Array-Methoden oder List-Methoden außerhalb von SQL verwenden können, um die Sammlung als Ganzes neu zu ordnen, aktualisieren Sie jeden Eintrag, oder Sie können herausfinden, wo Sie ihn einfügen. und +1 oder -1 für jeden Eintrag danach oder davor entsprechend.

Sobald Sie eine kleine Bibliothek dafür geschrieben haben, wird es ein Kinderspiel.


1

Ich würde einfach ein Bestellfeld einfügen. Es ist der einfachste Weg. Wenn der Kunde die Felder nachbestellen kann oder Sie sie in die Mitte einfügen müssen, schreiben Sie einfach die Bestellfelder für alle Artikel in diesem Stapel neu.

Wenn Sie diese Einschränkung später aufgrund der schlechten Leistung bei Einfügungen und Aktualisierungen feststellen, können Sie anstelle einer Ganzzahl ein Varchar-Feld verwenden. Dies ermöglicht ein recht hohes Maß an Präzision beim Einsetzen. Zum Einfügen zwischen den Elementen 'A' und 'B' können Sie beispielsweise ein Element einfügen, das als 'AA' bestellt wurde. Dies ist jedoch mit ziemlicher Sicherheit ein Overkill für einen Einkaufswagen.


Was kommt nach ZIhrer Varchar-Feldsortierung?
CDMckay

1

Auf einer Abstraktionsebene über dem Warenkorb können Sie beispielsweise CartOrder (mit CartItem 1-n) ein Feld namens itemOrder verwalten, das nur eine durch Kommas getrennte Liste der ID (PK) der relevanten cartItem-Datensätze sein kann. Auf der Anwendungsebene müssen Sie dies analysieren und Ihre Artikelmodelle entsprechend anordnen. Das große Plus für diesen Ansatz liegt im Fall von Umbesetzungen der Reihenfolge. Möglicherweise werden keine Änderungen an einzelnen Objekten vorgenommen. Da die Reihenfolge jedoch als Indexfeld in den Zeilen der Auftragselementtabelle beibehalten wird, müssen Sie für jedes der Objekte einen Aktualisierungsbefehl ausgeben Zeilen, die ihr Indexfeld aktualisieren. Bitte teilen Sie mir Ihre Kritik an diesem Ansatz mit. Ich bin gespannt, auf welche Weise dies fehlschlagen könnte.


1

Ich habe es pragmatisch so gelöst :

  1. Die Reihenfolge wird in der Benutzeroberfläche definiert.

  2. Das Backend erhält eine POST-Anforderung, die die IDs und die entsprechende Position jedes Elements in der Liste enthält.

  3. Ich starte eine Transaktion und aktualisiere die Position für jede ID.

Getan.

Die Bestellung ist also teuer, aber das Lesen der bestellten Liste ist super günstig.


0

Ich würde empfehlen, Lücken in der Bestellnummer zu halten. Verwenden Sie also anstelle von 1,2,3 usw. 10,20,30 ... Wenn Sie nur einen weiteren Artikel einfügen müssen, können Sie ihn auf 15 setzen, anstatt alles neu zu ordnen an diesem Punkt.


22
Das wäre nur in Ordnung, wenn Sie das System in BASIC
schreiben würden ;-)

10
Im Ernst, dieser Ansatz würde nur die Notwendigkeit einer tatsächlichen Sortierung verschieben, und dann haben Sie zwei verschiedene Funktionen in Ihrem Code. Wenn Sie wahrscheinlich irgendwann mit einer Sortierung fertig werden müssen, warum nicht einfach am Anfang und die Komplexität niedrig halten?
Belugabob

0

Nun, ich würde sagen, die kurze Antwort lautet:

Erstellen Sie einen Primärschlüssel für die Autoidentität in der Tabelle "cartcontents" und fügen Sie die Zeilen in der richtigen Reihenfolge von oben nach unten ein. Wenn Sie dann aus der Tabelle mit der Reihenfolge nach der Autoidentitätsspalte des Primärschlüssels auswählen, erhalten Sie dieselbe Liste. Auf diese Weise müssen Sie alle Artikel löschen und bei Änderungen am Warenkorbinhalt wieder einlegen. (Aber das ist immer noch eine ziemlich saubere Methode.) Wenn dies nicht möglich ist, gehen Sie zur Bestellspalte, wie von anderen vorgeschlagen.


-1

Wenn ich a verwende Hibernateund die Reihenfolge von a speichern muss @OneToMany, verwende ich a Mapund nicht a List.

@OneToMany(fetch = FetchType.EAGER, mappedBy = "rule", cascade = CascadeType.ALL)
@MapKey(name = "position")
@OrderBy("position")
private Map<Integer, RuleAction>    actions             = LazyMap.decorate(new LinkedHashMap<>(), FactoryUtils.instantiateFactory(RuleAction.class, new Class[] { Rule.class }, new Object[] { this }));

In diesem Java-Beispiel positionhandelt es sich um eine Integer-Eigenschaft, RuleActionsodass die Reihenfolge auf diese Weise beibehalten wird. Ich denke in C # würde dies ziemlich ähnlich aussehen.

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.