2008-12-01 17 views
63

Me preguntaba si alguien tiene una buena solución a un problema que he encontrado en numerosas ocasiones durante los últimos años.La mejor manera de guardar una lista ordenada en la base de datos mientras se guarda el pedido

Tengo un carro de compras y mi cliente solicita explícitamente que su pedido sea significativo. Entonces necesito persistir el pedido al DB.

La manera obvia sería simplemente insertar algún campo de órdenes donde asignaría el número 0 a N y ordenarlo de esa manera.

Pero hacerlo dificultaría más el reordenamiento y de alguna manera siento que esta solución es algo frágil y volverá a surgir algún día.

(yo uso C# 3.5 con NHibernate y SQL Server 2005)

Gracias

Respuesta

22

Fwiw, creo que la forma usted sugiere (es decir, cometer el fin de la base de datos) no es una mala solución a tu problema También creo que es probablemente la forma más segura/más confiable.

+1

De alguna manera siento que mantener ese orden puede causar dolores de cabeza en el futuro. Entonces pregunté y quizás alguien encuentre una mejor solución. – Tigraine

+13

No se preocupe, no hay mejor manera que usar la columna de pedidos. En cuanto a los futuros dolores de cabeza ... no intente optimizar para los casos de uso de los que no tenga conocimiento. –

+1

Dado que normalmente busca todo el carrito para fines de visualización, renumerar todo el carrito no parece ser realmente un problema –

0

Recomendaría mantener huecos en el número de orden, así que en vez de 1,2,3 etc., use 10,20,30 ... Si necesita insertar solo un elemento más, puede ponerlo a 15, en lugar de reordenar todo en ese punto.

+20

Eso solo estaría bien si escribieras el sistema en BASIC ;-) – belugabob

+10

Hablando en serio, este enfoque solo pospondrá la necesidad de hacer un tipo, y luego tienes dos bits diferentes de funcionalidad en tu código. Si probablemente tendrá que realizar algún tipo de tarea en algún momento, ¿por qué no hacerlo desde el principio y mantener bajo el nivel de complejidad? – belugabob

5

Desafortunadamente no hay una solución mágica para esto. No puede garantizar el orden de ninguna declaración SELECT SIN una cláusula order by. Necesita agregar la columna y el programa a su alrededor.

No sé si recomendaría agregar huecos en la secuencia de orden, dependiendo del tamaño de sus listas y de los hits en el sitio, es posible que gane muy poco por el manejo excesivo de la lógica (todavía necesitamos atender la ocasión en la que se hayan agotado todas las lagunas). Echaré un vistazo de cerca para ver qué beneficios esto te daría en tu situación.

Lo siento, no puedo ofrecer nada mejor, espero que esto ayude.

+2

Dado que normalmente busca todo el carrito para mostrarlo, la renumeración de todo el carrito no parece ser realmente un problema. –

+1

Si la lista resulta ser lo suficientemente grande como para no actualizar cada fila al reordenar algo, es posible que pueda utilizar una columna DisplayOrder de coma flotante. No lo he intentado pero es solo una idea ... –

1

Me gustaría insertar un campo de orden. Es la forma más simple. Si el cliente puede reordenar los campos o necesita insertarlos en el medio, simplemente reescriba los campos de pedidos para todos los artículos en ese lote.

Si por debajo de la línea se encuentra esta limitación debido al bajo rendimiento en las inserciones y actualizaciones, entonces es posible utilizar un campo varchar en lugar de un número entero. Esto permite un alto nivel de precisión cuando se inserta. por ejemplo, para insertar entre los elementos "A" y "B" puede insertar un artículo ordenado como "AA". Sin embargo, esto es casi demasiado caro para un carrito de compras.

+0

¿Qué viene después de 'Z' en tu clasificación de campo varchar? – cdmckay

0

Bueno, yo diría que la respuesta corta es:

crear una clave principal de autoidentity en la tabla cartcontents, a continuación, insertar filas en el orden de arriba hacia abajo correcta. Luego, al seleccionar de la tabla con el orden de la columna de autoidentidad de la clave principal, obtendrá la misma lista. Al hacer esto, debe eliminar todos los elementos y volver a insertarlos en caso de alteraciones en el contenido del carrito. (Pero esa es una forma bastante limpia de hacerlo). Si eso no es factible, vaya a la columna de pedidos como sugirieron otros.

3

No recomendaría el enfoque A, AA, B, BA, BB en absoluto. Hay un montón de procesamiento adicional involucrado para determinar la jerarquía y la inserción de entradas en el medio no es nada divertido.

Solo agregue un campo de orden, entero.No use huecos, porque entonces tiene que trabajar con un 'paso' no estándar en su siguiente inserción del medio, o tendrá que volver a sincronizar su lista primero, luego agregar una nueva entrada.

Tener 0 ... N es fácil de reordenar, y si puede usar métodos de matriz o métodos de lista fuera de SQL para reordenar la colección como un todo, entonces actualice cada entrada, o puede averiguar dónde están insertando en, y +1 o -1 cada entrada después o antes de eso en consecuencia.

Una vez que tenga una pequeña biblioteca escrita, será un pedazo de pastel.

1

En un nivel de abstracción por encima del carrito Elementos digamos CartOrder (que tiene 1-n con CartItem) puede mantener un campo llamado itemOrder que podría ser solo una lista de ID (PK) separada por comas de los registros cartItem relevantes . Será en la capa de aplicación lo que requiera para analizar eso y organizar sus modelos de elementos en consecuencia. La gran ventaja de este enfoque será en el caso de reorganizaciones de pedidos, puede que no haya cambios en los objetos individuales, pero dado que el orden se conserva como un campo de índice dentro de las filas de la tabla de elementos de orden, deberá emitir un comando de actualización para cada uno de los filas actualizando su campo de índice. Háganme saber sus críticas sobre este enfoque, tengo curiosidad por saber de qué manera podría fallar.

9

¿Qué le parece usar una implementación de lista enlazada? Al tener una columna, se mantendrá el valor (número de orden) del siguiente elemento. Creo que es de lejos el más fácil de usar al hacer la inserción de pedidos en el medio. No es necesario volver a numerar.

30

La mejor solución es un Doubly Linked list. O (1) para todas las operaciones excepto la indexación. Nada puede indexar SQL rápidamente, excepto una cláusula where en el elemento que desee.

0,10,20 tipos fallan. Los de la columna de secuencia fallan. La columna de secuencia flotante falla en movimientos de grupo.

Doblemente Lista enlazada es las mismas operaciones para la adición, eliminación, eliminación de grupo, adición de grupo, movimiento de grupo. La lista de enlaces individuales funciona bien también. Doble enlace es mejor con SQL en mi opinión, sin embargo. La lista de enlaces individuales requiere que tenga toda la lista.

+3

Esta es la mejor solución en mi humilde opinión. Por ejemplo, tengo más de 300 películas en mi cola de Netflix. Si muevo un artículo desde la posición 297 a la parte superior, netflix no tendría que hacer 300 actualizaciones. Solo 3 actualizaciones en el mejor de los casos – user35559

+6

¿Cuál es la mejor manera de obtener los primeros 50 artículos? ¿Debo leerlos uno a uno, o hay alguna solución mágica de sql? – akn

+0

@akn Esto sería posible usando una consulta recursiva y luego limitando el número de filas por 50 para obtener las primeras 50 filas. –

46

Ok, esta es mi solución para hacer que la programación sea más fácil para cualquiera que pase por este hilo. el truco está en poder actualizar todos los índices de orden por encima o por debajo de una inserción/eliminación en una actualización.

Usando una columna numérica (número entero) en su mesa, con el apoyo de la consulta SQL de

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

Para eliminar el tema en orderindex 6:

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

Para intercambiar dos elementos (4 y 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; 

es decir, 0 no se utiliza, a fin de utilizar un como un maniquí para evitar tener un elemento ambiguo.

Para insertar a las 3:

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

Cuando uso Hibernate, y la necesidad de guardar el orden de un @OneToMany, utilizo un Map y no un 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 })); 

En este ejemplo de Java, position es una propiedad de entero de RuleAction lo que el orden se conserva de esa manera. Creo que en C# esto se vería bastante similar.

1

Lo resuelto pragmáticamente así:

  1. El orden se define en la interfaz de usuario.

  2. El servidor recibe una solicitud POST que contiene los ID y la posición correspondiente de cada elemento de la lista.

  3. Empiezo una transacción y actualizo la posición de cada ID.

Hecho.

El pedido es caro, pero leer la lista ordenada es muy barato.

Cuestiones relacionadas