Лучший способ сохранить упорядоченный список в базе данных, сохраняя порядок
-
11-07-2019 - |
Вопрос
Мне было интересно, есть ли у кого-нибудь хорошее решение проблемы, с которой я сталкивался много раз за последние годы.
У меня есть корзина для покупок, и мой клиент явно требует, чтобы ее заказ был значительным.Поэтому мне нужно сохранить заказ в БД.
Очевидным способом было бы просто вставить некоторый 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. Это будет на прикладном уровне, который вам потребуется проанализировать и соответствующим образом упорядочить ваши модели элементов. Большим плюсом для этого подхода будет случай перестановок порядка, возможно, не будет изменений в отдельных объектах, но так как порядок сохраняется как поле индекса в строках таблицы элементов порядка, вам нужно будет выполнить команду обновления для каждого из строки обновляют свое индексное поле. Пожалуйста, дайте мне знать вашу критику в отношении этого подхода, мне любопытно узнать, каким образом это может потерпеть неудачу. Р>
я решил это прагматично так:
Порядок определяется в пользовательском интерфейсе.
Серверная часть получает запрос POST, содержащий идентификаторы и соответствующую позицию каждого элемента в списке.
Я запускаю транзакцию и обновляю позицию для каждого идентификатора.
Сделанный.
Таким образом, заказ стоит дорого, но чтение заказанного списка обходится очень дешево.
Я бы порекомендовал оставить пробелы в номере заказа, поэтому вместо 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 # это будет выглядеть довольно похоже.