Meilleure façon de sauvegarder une liste commandée dans la base de données tout en conservant l'ordre

StackOverflow https://stackoverflow.com/questions/330482

Question

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 soit importante. Il faut donc que je répète l'ordre dans la base de données.

La méthode la plus évidente consiste simplement à insérer un champ OrderField dans lequel je vais attribuer le nombre 0 à N et le trier de cette façon.

Mais cela rendrait les commandes plus difficiles et j’ai l’impression que cette solution est un peu fragile et qu’elle me reviendra un jour.

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

Merci

Était-ce utile?

La solution

FWIW, je pense que la façon que vous suggérez (c’est-à-dire l’enregistrement 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 moyen le plus sûr et le plus fiable.

Autres conseils

Ok, voici ma solution pour rendre la programmation plus facile pour tous ceux qui suivent ce fil. l'astuce consiste à pouvoir mettre à jour tous les index d'ordre au-dessus ou au-dessous d'une insertion / suppression en une seule mise à jour.

Utilisation d'une colonne numérique (entier) 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 permuter 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;

i.e. 0 n'est pas utilisé, utilisez-le comme un mannequin pour éviter d'avoir un élément ambigu.

Pour insérer en 3:

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

La meilleure solution est une liste à double accès . O (1) pour toutes les opérations sauf l'indexation. Toutefois, rien ne permet d’indexer rapidement le code SQL, à l’exception d’une clause where sur l’élément souhaité.

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

La liste Doubly Linked comprend les mêmes opérations d’ajout, de suppression, de suppression de groupe, d’ajout de groupe et de déplacement de groupe. La liste simple liée fonctionne bien aussi. La double liaison est meilleure avec SQL à mon avis cependant. Une liste chaînée unique nécessite la totalité de la liste.

Comment utiliser une implémentation de liste chaînée? Ayant une colonne le tiendra la valeur (numéro de commande) du prochain article. Je pense que c'est de loin le plus facile à utiliser pour l'insertion de commandes entre les deux. Pas besoin de renuméroter.

Malheureusement, il n’ya pas de solution miracle à ce problème. Vous ne pouvez pas garantir l'ordre d'une instruction SELECT SANS une clause order by. Vous devez ajouter la colonne et programmer autour d'elle.

Je ne sais pas si je recommanderais d’ajouter des espaces dans la séquence de commandes. En fonction de la taille de vos listes et des hits sur le site, vous pourriez en tirer très peu pour la gestion de la logique (vous ' d doivent encore répondre à l’occasion où toutes les lacunes ont été utilisées). Je regarderais de près pour voir quels avantages cela vous apporterait dans votre situation.

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

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

Ajoutez simplement un OrderField, un entier. N'utilisez pas d'espaces vides, car vous devrez alors utiliser une "étape" non standard lors de votre prochaine insertion au milieu ou vous devrez d'abord resynchroniser votre liste, puis ajouter une nouvelle entrée.

Avoir 0 ... N est facile à réorganiser, et si vous pouvez utiliser des méthodes Array ou List en dehors de SQL pour réorganiser la collection dans son ensemble, mettez à jour chaque entrée, ou vous pouvez déterminer où vous vous trouvez. insertion dans, et +1 ou -1 chaque entrée après ou avant en conséquence.

Une fois que vous aurez écrit une petite bibliothèque, ce sera un morceau de gâteau.

Je voudrais simplement insérer un champ de commande. C'est le moyen le plus simple. Si le client peut réorganiser les champs ou si vous devez l'insérer au milieu, il suffit de réécrire les champs de commande pour tous les articles de ce lot.

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

À un niveau d'abstraction au-dessus du panier Articles, disons CartOrder (qui a 1-n avec CartItem), vous pouvez gérer un champ appelé itemOrder qui pourrait être simplement une liste d'id (PK) d'enregistrements cartItem pertinents. Ce sera au niveau de l'application que vous devez analyser et organiser vos modèles d'éléments en conséquence. Le gros plus de cette approche sera en cas de remaniement d’ordre, il se peut qu’il n’y ait pas de changements sur des objets individuels mais puisque l’ordre est conservé en tant que champ d’index à l’intérieur des lignes de la table des postes de commande, vous devrez émettre une commande de mise à jour pour chacun des éléments. lignes mettant à jour leur champ d'index.    S'il vous plaît laissez-moi savoir vos critiques sur cette approche, je suis curieux de savoir de quelle manière cela pourrait échouer.

Je l'ai résolu de manière pragmatique comme suit:

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

  2. Le serveur reçoit une demande POST contenant les identifiants et la position correspondante de chaque élément de la liste.

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

Terminé.

La commande est donc coûteuse, mais la liste commandée est très économique.

Je recommanderais de conserver les espaces dans le numéro de commande. Ainsi, au lieu de 1, 2, 3, utilisez 10,20,30 ... Si vous devez simplement insérer un autre élément, vous pouvez le mettre à 15, plutôt que de tout réorganiser à ce moment-là.

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

Créez une clé primaire d’identité automatique dans la table cartcontents, puis insérez les lignes dans le bon ordre descendant. Ensuite, en sélectionnant dans la table avec ordre par colonne de clé primaire, la colonne d’identité automatique vous donnerait la même liste. Ce faisant, vous devez supprimer tous les articles et les réinsérer en cas de modification du contenu du panier. (Mais c’est quand même une façon de le faire.) Si cela n’est pas faisable, choisissez la colonne de commande comme suggéré par d’autres.

Lorsque j'utilise Hibernate et que je dois enregistrer la commande d'un @OneToMany , j'utilise un Map et non un . Liste .

@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 , de sorte que l'ordre est conservé de cette façon. Je suppose qu'en C #, cela aurait plutôt l'air similaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top