La mejor manera de guardar una lista ordenada en la base de datos mientras se mantiene el pedido

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

Pregunta

Me preguntaba si alguien tiene una buena solución a un problema que he encontrado en numerosas ocasiones durante los últimos años.

Tengo un carrito de compras y mi cliente solicita explícitamente que su pedido sea significativo. Entonces necesito persistir el pedido a la base de datos.

La forma obvia sería simplemente insertar un OrderField donde asignaría el número 0 a N y ordenarlo de esa manera.

Pero hacerlo haría más difícil la reordenación y de alguna manera siento que esta solución es un poco frágil y volverá a mí algún día.

(uso C # 3,5 con NHibernate y SQL Server 2005)

Gracias

¿Fue útil?

Solución

FWIW, creo que la forma en que sugieres (es decir, confirmar el pedido a la base de datos) no es una mala solución a tu problema. También creo que es probablemente la forma más segura / confiable.

Otros consejos

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

Usando una columna numérica (entera) en su tabla, soportada por las consultas SQL

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

Para eliminar el elemento en el índice de pedido 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 usa, así que úsalo como un ficticio para evitar tener un elemento ambiguo.

Para insertar en 3:

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

La mejor solución es una Lista doblemente vinculada . O (1) para todas las operaciones excepto la indexación. Sin embargo, nada puede indexar SQL rápidamente, excepto una cláusula where en el elemento que desea.

0,10,20 tipos fallan. La columna de secuencia falla. La columna de secuencia flotante falla en los movimientos grupales.

La lista doblemente enlazada es la misma operación de adición, eliminación, eliminación de grupo, adición de grupo, movimiento de grupo. Lista enlazada única funciona bien también. Sin embargo, el doble enlace es mejor con SQL en mi opinión. La lista vinculada individual requiere que tenga toda la lista.

¿Qué tal usar una implementación de lista vinculada? Tener una columna contendrá el valor (número de pedido) del siguiente artículo. Creo que es, con mucho, el más fácil de usar cuando se insertan órdenes intermedias. No es necesario volver a numerar.

Desafortunadamente no hay una bala mágica para esto. No puede garantizar el orden de ninguna instrucción SELECT SIN una orden por cláusula. Debe agregar la columna y el programa a su alrededor.

No sé si recomendaría agregar espacios en la secuencia de orden, dependiendo del tamaño de sus listas y los resultados en el sitio, podría ganar muy poco por la sobrecarga de manejar la lógica (usted ' d todavía necesita atender la ocasión donde se han agotado todas las brechas). Echaría un vistazo de cerca para ver qué ventajas le daría esto en su situación.

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

No recomendaría el enfoque A, AA, B, BA, BB en absoluto. Hay una gran cantidad de procesamiento adicional involucrado para determinar la jerarquía e insertar entradas intermedias no es nada divertido.

Simplemente agregue un OrderField, entero. No use espacios en blanco, ya que entonces debe trabajar con un 'paso' no estándar en su siguiente inserción intermedia, o tendrá que resincronizar su lista primero y luego agregar una nueva entrada.

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

Una vez que tenga una pequeña biblioteca escrita, será pan comido.

Simplemente insertaría un campo de orden. Es la forma más simple. Si el cliente puede reordenar los campos o si necesita insertarlos en el medio, simplemente vuelva a escribir los campos de pedido para todos los artículos en ese lote.

Si en el futuro encuentra esta limitación debido al bajo rendimiento de las inserciones y actualizaciones, entonces es posible usar un campo varchar en lugar de un entero. Esto permite un nivel bastante alto de precisión al insertar. por ejemplo, para insertar entre los elementos 'A' y 'B' puede insertar un elemento ordenado como 'AA'. Sin embargo, esto es casi una exageración para un carrito de compras.

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

Lo resolví pragmáticamente de esta manera:

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

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

  3. Comienzo una transacción y actualizo la posición para cada ID.

Hecho.

Por lo tanto, ordenar es costoso, pero leer la lista ordenada es muy barato.

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

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

Cree una clave principal de autoidentidad en la tabla de contenido del carrito, luego inserte filas en el orden correcto de arriba hacia abajo. Luego, al seleccionar de la tabla con el orden de la columna de autoidentidad de clave principal, obtendría la misma lista. Al hacer esto, debe eliminar todos los artículos y volver a insertarlos en caso de alteraciones en el contenido del carrito. (Pero esa sigue siendo una forma bastante limpia de hacerlo) Si eso no es factible, vaya con la columna de orden como lo sugirieron otros.

Cuando uso Hibernate y necesito guardar el orden de un @OneToMany , uso un Map y no un Lista .

@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 Integer de RuleAction , por lo que el orden persiste de esa manera. Supongo que en C # esto se vería bastante similar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top