Лучший способ сохранить упорядоченный список в базе данных, сохраняя порядок

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

Вопрос

Мне было интересно, есть ли у кого-нибудь хорошее решение проблемы, с которой я сталкивался много раз за последние годы.

У меня есть корзина для покупок, и мой клиент явно требует, чтобы ее заказ был значительным.Поэтому мне нужно сохранить заказ в БД.

Очевидным способом было бы просто вставить некоторый OrderField, где я бы присвоил номер 0 N и отсортировал его таким образом.

Но это усложнит переупорядочение, и я почему-то чувствую, что это решение довольно хрупкое и когда-нибудь вернется ко мне.

(Я использую C# 3,5 с NHibernate и SQL Server 2005)

Спасибо

Это было полезно?

Решение

FWIW, я думаю, способ, которым вы предлагаете (то есть, отправляете заказ в базу данных), не является плохим решением вашей проблемы. Я также думаю, что это, вероятно, самый безопасный / самый надежный способ.

Другие советы

Хорошо, вот мое решение, которое упростит программирование для всех, кто попадает в эту тему.Хитрость заключается в том, чтобы обновить все индексы порядка выше или ниже вставки/удаления за одно обновление.

Использование числового (целочисленного) столбца в таблице, поддерживаемого запросами SQL.

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

Чтобы удалить элемент с индексом заказа 6:

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

Чтобы поменять местами два элемента (4 и 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;

то есть0 не используется, поэтому используйте его в качестве фиктивного, чтобы избежать неоднозначного элемента.

Чтобы вставить в 3:

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

Лучшим решением является список с двойной связью . O (1) для всех операций, кроме индексации. Ничто не может быстро проиндексировать SQL, за исключением предложения where для нужного элемента.

0,10,20 типов терпят неудачу. Последовательности столбцов не работают. Столбец последовательности с плавающей точкой не выполняется при групповых перемещениях.

Вдвойне связанный список - это те же операции для добавления, удаления, удаления группы, добавления группы, перемещения группы. Единый связанный список тоже работает нормально. По моему мнению, двойная связь лучше с SQL. Единый связанный список требует, чтобы у вас был полный список.

Как насчет использования реализации связанного списка? Наличие одного столбца будет содержать значение (номер заказа) следующего элемента. Я думаю, что это гораздо проще использовать при вставке заказов между ними. Не нужно перенумеровывать.

К сожалению, для этого нет волшебной пули. Вы не можете гарантировать порядок любого оператора SELECT БЕЗ заказа по предложению. Вам нужно добавить колонку и программировать вокруг нее.

Я не знаю, что я бы порекомендовал добавить пробелы в последовательности заказов, в зависимости от размера ваших списков и посещений сайта, вы можете получить очень мало за накладные расходы по обработке логики (вы ' Я все еще должен учесть случай, когда все пробелы были использованы). Я бы внимательно посмотрел, чтобы увидеть, какие преимущества это даст вам в вашей ситуации.

Извините, я не могу предложить ничего лучше, надеюсь, это помогло.

Я бы вообще не рекомендовал подходы A, AA, B, BA, BB. Для определения иерархии требуется много дополнительной обработки, и вставка записей между ними совсем не увлекательна.

Просто добавьте OrderField, целое число. Не используйте пробелы, потому что тогда вам придется либо работать с нестандартным «шагом» на следующей средней вставке, либо вам придется сначала повторно синхронизировать ваш список, а затем добавить новую запись.

Наличие 0 ... N легко переупорядочить, и если вы можете использовать методы Array или List вне SQL, чтобы переупорядочить коллекцию в целом, то обновите каждую запись, или вы можете выяснить, где вы находитесь вставка в, и +1 или -1 каждая запись после или перед ней соответственно.

Если у вас есть небольшая библиотека, написанная для этого, это будет кусок пирога.

Я бы просто вставил поле заказа. Это самый простой способ. Если клиент может изменить порядок полей или вам нужно вставить его посередине, просто перепишите поля заказа для всех позиций в этом пакете.

Если в дальнейшем вы обнаружите это ограничение из-за низкой производительности при вставках и обновлениях, тогда можно использовать поле varchar, а не целое число. Это обеспечивает довольно высокий уровень точности при вставке. Например, для вставки между элементами «A» и «B» вы можете вставить элемент, обозначенный как «AA». Это почти наверняка излишне для корзины покупок.

На уровне абстракции над корзиной Items, скажем, CartOrder (который имеет 1-n с CartItem), вы можете поддерживать поле под названием itemOrder, которое может быть просто разделенным запятыми списком идентификаторов (PK) соответствующих записей cartItem. Это будет на прикладном уровне, который вам потребуется проанализировать и соответствующим образом упорядочить ваши модели элементов. Большим плюсом для этого подхода будет случай перестановок порядка, возможно, не будет изменений в отдельных объектах, но так как порядок сохраняется как поле индекса в строках таблицы элементов порядка, вам нужно будет выполнить команду обновления для каждого из строки обновляют свое индексное поле.    Пожалуйста, дайте мне знать вашу критику в отношении этого подхода, мне любопытно узнать, каким образом это может потерпеть неудачу.

я решил это прагматично так:

  1. Порядок определяется в пользовательском интерфейсе.

  2. Серверная часть получает запрос POST, содержащий идентификаторы и соответствующую позицию каждого элемента в списке.

  3. Я запускаю транзакцию и обновляю позицию для каждого идентификатора.

Сделанный.

Таким образом, заказ стоит дорого, но чтение заказанного списка обходится очень дешево.

Я бы порекомендовал оставить пробелы в номере заказа, поэтому вместо 1,2,3 и т. д. используйте 10,20,30 ... Если вам нужно просто вставить еще один элемент, вы можете поставить его на 15, скорее чем переупорядочить все на этом этапе.

Ну, я бы сказал, короткий ответ:

Создайте первичный ключ автоматической идентификации в таблице cartcontents, затем вставьте строки в правильном порядке сверху вниз. Тогда при выборе из таблицы с порядком по первичному ключу столбец автоидентификации выдаст вам тот же список. Делая это, вы должны удалить все элементы и затем повторно вставить их в случае изменения содержимого корзины. (Но это все еще довольно чистый способ сделать это). Если это неосуществимо, тогда воспользуйтесь колонкой заказа, как предложено другими.

Когда я использую Hibernate и мне нужно сохранить порядок @OneToMany , я использую Map , а не Список .

@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 }));

В этом примере Java position является свойством Integer для RuleAction , поэтому порядок сохраняется таким образом. Я предполагаю, что в C # это будет выглядеть довольно похоже.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top