Meilleure façon d'enregistrer une liste ordonnée dans la base de données tout en conservant la commande

Je me demandais si quelqu'un avait une bonne solution à un problème que j'ai rencontré à plusieurs reprises au cours des dernières années.

J'ai un panier et mon client demande explicitement que sa commande est significative. J'ai donc besoin de persister l'ordre à la base de données.

La manière évidente serait d'insérer simplement un champ OrderField où j'attribuerais le nombre 0 à N et de le trier de cette façon.

Mais cela rendrait la réorganisation plus difficile et je pense en quelque sorte que cette solution est un peu fragile et reviendra à moi un jour.

(j'utilise C # 3,5 avec NHibernate et SQL Server 2005)

Merci

64
demandé sur Machavity 2008-12-01 13:40:42

12 réponses

FWIW, je pense que la façon dont vous suggérez (c'est-à-dire la validation de la commande dans la base de données) n'est pas une mauvaise solution à votre problème. Je pense aussi que c'est probablement le plus sûr/la plus fiable.

23
répondu Galwegian 2008-12-01 10:45:09

Ok voici ma solution pour rendre la programmation plus facile pour tous ceux qui se produisent le long de ce fil. l'astuce est de pouvoir mettre à jour tous les index d'ordre au-dessus ou au-dessous d'une insertion / suppression dans une mise à jour.

Utilisation d'une colonne numérique (entière) dans votre table, prise en charge par les requêtes SQL

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

Pour supprimer l'élément à orderindex 6:

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

Pour échanger deux éléments (4 et 7):

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

C'est-à-dire 0 n'est pas utilisé, alors utilisez - le comme un mannequin pour éviter d'avoir une ambiguïté article.

À insérer à 3:

 UPDATE myitems SET orderindex = (orderindex + 1) WHERE orderindex > 2;
 INSERT INTO myitems (Myitem,orderindex) values ("MytxtitemHere",3)
46
répondu Kickaha 2012-05-21 04:33:33

La meilleure solution est une liste doublement liée . O (1) pour toutes les opérations sauf l'indexation. Rien ne peut indexer SQL rapidement, sauf une clause where sur l'élément que vous voulez.

0,10,20 types échouent. Les colonnes de séquence échouent. La colonne de séquence flottante échoue lors des mouvements de groupe.

Liste doublement liée est les mêmes opérations pour addition, suppression, suppression de groupe, ajout de groupe, déplacement de groupe. Une seule liste liée fonctionne aussi bien. Double linked est mieux avec SQL à mon avis cependant. Liée unique liste vous oblige à avoir la liste complète.

30
répondu sean wagner 2013-12-20 21:54:37

Que diriez-vous d'utiliser une implémentation de liste liée? Ayant une colonne, le contiendra la valeur (numéro de commande) de l'article suivant. Je pense que c'est de loin le plus facile à utiliser lors de l'insertion de commandes entre les deux. Pas besoin de renuméroter.

9
répondu Js. 2010-02-19 01:09:17

Malheureusement, il n'y a pas de Balle magique pour cela. Vous ne pouvez pas garantir l'ordre d'une instruction SELECT sans clause order by. Vous devez ajouter la colonne et programmer autour d'elle.

Je ne sais pas que je recommanderais d'ajouter des lacunes dans la séquence d'ordre, en fonction de la taille de vos listes et des hits sur le site, vous pourriez gagner très peu pour la gestion de la logique (vous auriez encore besoin de répondre à l'occasion où toutes les lacunes ont été épuisées). Je prendrais un proche regardez pour voir quels avantages cela vous donnerait dans votre situation.

Désolé, Je ne peux rien offrir de mieux, J'espère que cela a aidé.

5
répondu Binary Worrier 2013-04-23 06:43:25

Je ne recommanderais pas du tout L'approche A, AA, B, BA, BB. Il y a beaucoup de traitement supplémentaire impliqué pour déterminer la hiérarchie et insérer des entrées entre les deux n'est pas amusant du tout.

Il suffit d'ajouter un OrderField, entier. N'utilisez pas de lacunes, car vous devez soit travailler avec une "étape" non standard sur votre prochaine insertion du milieu, soit vous devrez d'abord resynchroniser votre liste, puis Ajouter une nouvelle entrée.

Ayant 0...N est facile à réorganiser, et si vous pouvez utiliser des méthodes de tableau ou de liste méthodes en dehors de SQL pour réorganiser la collection dans son ensemble, puis mettre à jour chaque entrée, ou vous pouvez comprendre où vous insérez, et +1 ou -1 chaque entrée après ou avant en conséquence.

Une fois que vous avez une petite bibliothèque écrite pour elle, ce sera un morceau de gâteau.

3
répondu Adam 2008-12-02 18:59:34

Je voudrais simplement insérer un champ de commande. De ses la façon la plus simple. Si le client peut réorganiser les champs ou si vous devez les insérer au milieu, il suffit de réécrire les champs de commande pour tous les éléments de ce lot.

Si en bas de la ligne vous trouvez cette limitation en raison de mauvaises performances sur les insertions et les mises à jour, il est possible d'utiliser un champ varchar plutôt qu'un entier. Cela permet un niveau de précision assez élevé lors de l'insertion. par exemple, pour insérer entre les éléments " A " et "B", vous pouvez insérez un élément de commandé comme "AA". C'est presque certainement exagéré pour un panier.

1
répondu Jack Ryan 2008-12-01 11:38:14

Sur un niveau d'abstraction au-dessus des éléments du panier disons CartOrder (qui a 1 - N avec CartItem) vous pouvez maintenir un champ appelé itemOrder qui pourrait être juste une liste séparée par des virgules d'id(PK) des enregistrements cartItem pertinents . Ce sera à la couche d'application que vous aurez besoin d'analyser cela et d'organiser vos modèles d'éléments en conséquence . Le gros plus pour cette approche sera en cas de remaniement d'ordre, il pourrait ne pas y avoir de changements sur des objets individuels mais puisque l'ordre est persistant en tant qu'index champ dans les lignes de la table des éléments de commande, vous devrez émettre une commande de mise à jour pour chacune des lignes mettant à jour leur champ d'index. Veuillez me faire part de vos critiques sur cette approche, je suis curieux de savoir de quelle manière cela pourrait échouer.

1
répondu redzedi 2009-08-03 07:19:09

Je l'ai résolu , de façon pragmatique, comme ceci:

  1. L'ordre est défini dans l'INTERFACE utilisateur.

  2. Le backend obtient une requête POST qui contient les ID et la Position correspondante de chaque élément de la liste.

  3. Je commence une transaction et met à jour la position pour chaque ID.

C'est fait.

La commande est donc coûteuse mais la lecture de la liste commandée est super bon marché.

1
répondu Bijan 2015-07-21 12:47:51

Je recommande de garder les lacunes dans le numéro de commande, donc au lieu de 1,2,3 etc, Utilisez 10,20,30... Si vous devez simplement insérer un élément de plus, vous pouvez le mettre à 15, plutôt que de tout réorganiser à ce stade.

0
répondu harriyott 2008-12-01 10:47:59

Eh Bien, je dirais que la réponse courte est:

Créez une clé primaire d'autoidentity dans la table cartcontents, puis insérez des lignes dans l'ordre descendant correct. Ensuite, en sélectionnant dans la table avec l'ordre par la colonne autoidentity clé primaire vous donnerait la même Liste. En faisant cela, vous devez supprimer tous les éléments et réinsérer puis en cas de modifications au contenu du panier. (Mais c'est encore une façon assez propre de le faire) si ce n'est pas faisable, alors allez avec la colonne order comme suggéré par d'autres.

0
répondu sindre j 2008-12-01 11:48:59

Lorsque j'utilise Hibernate, et la nécessité de sauvegarder l'ordre de @OneToMany, j'utilise un Map et pas 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 }));

Dans cet exemple Java, position est une propriété entière de RuleAction donc l'ordre est conservé de cette façon. Je suppose qu'en C # cela aurait l'air plutôt similaire.

-1
répondu yglodt 2016-01-19 12:33:07