在保持排序的同时将已排序的 List 保存到数据库的最佳方法

我想知道是否有人有一个好的解决方案来解决我在过去几年中遇到过无数次的问题。

我有一个购物车,我的客户明确要求它的订单是重要的。所以我需要将订单持久化到数据库。

显而易见的方法是简单地插入一些 OrderField,其中我将数字0赋给 N,并按照这种方式对它进行排序。

但是这样做会使重新排序更加困难,而且我不知怎么地觉得这个解决方案有点脆弱,总有一天会回来找我的。

(我在 NHibernate 和 SQLServer2005中使用 C # 3、5)

谢谢你

29329 次浏览

FWIW,我认为您建议的方式(即将订单提交到数据库)对于您的问题来说是一个不错的解决方案。我也认为这可能是最安全/最可靠的方法。

我建议在订单数中保持间隔,所以不要用1、2、3等等,而是用10、20、30... ... 如果你需要再插入一个项目,你可以把它放在15,而不是在那一点重新排序所有的项目。

不幸的是,没有什么灵丹妙药可以解决这个问题。如果没有 order by 子句,则不能保证任何 SELECT语句的顺序。您需要添加列并围绕它编写程序。

我不知道我是否会建议在排序顺序中加入间隔,这取决于你的列表的大小和网站上的点击量,你可能会因为处理逻辑的过度开销而获得很少的收益(你仍然需要满足所有间隔已经用完的情况)。我会仔细看看这对你的情况有什么好处。

对不起,我不能提供更好的东西,希望这有帮助。

我只需要插入一个订单字段。这是最简单的方法。如果客户可以重新排序字段,或者您需要在中间插入,那么只需重写该批中所有项目的订单字段。

如果由于在插入和更新方面的性能较差,您发现这个限制,那么可以使用 varchar 字段而不是整数。这允许在插入时具有相当高的精度。例如,在“ A”和“ B”之间插入一个项目,你可以插入一个项目,命令为“ AA”。不过,对于一辆购物车来说,这几乎肯定是杀伤力过大。

简而言之:

在 cartcontent 表中创建一个自动标识的主键,然后按照正确的自顶向下顺序插入行。然后,通过按主键自动标识列的顺序从表中进行选择,将得到相同的列表。通过这样做,您必须删除所有项目,然后重新插入的情况下,改变购物车的内容。(但这仍然是一种相当干净的做法)如果这不可行,那么就按照其他人建议的顺序列。

我根本不推荐 A,AA,B,BA,BB 的方法。确定层次结构涉及到很多额外的处理,在其中插入条目一点也不有趣。

只要添加一个 OrderField,整数。不要使用间隔,因为那样的话,您要么在下一个中间插入中使用非标准的“步骤”,要么必须首先重新同步列表,然后添加一个新条目。

有0... N 很容易重新排序,如果你可以使用 SQL 之外的 Array 方法或 List 方法来重新排序集合作为一个整体,然后更新每个条目,或者你可以找出你插入到,+ 1或 -1每个条目之后或之前相应。

一旦你为它写了一个小图书馆,它将是一块蛋糕。

在 cartItem 之上的抽象级别上,假设 CartOrder (对于 CartItem 有1-n) ,您可以维护一个名为 itemOrder 的字段,该字段可以只是一个用逗号分隔的 cartItem 相关记录的 id (PK)列表。您需要在应用程序层解析它并相应地安排项模型。这种方法的最大优点是在顺序重组的情况下,可能不会对单个对象进行更改,但是由于顺序是作为订单项表行中的索引字段保持的,因此必须为每个更新其索引字段的行发出 update 命令。 请让我知道你对这种方法的批评意见,我很好奇在哪些方面可能会失败。

使用链表实现如何?有一列将保存下一个项目的值(订单号)。我认为它是目前为止最容易使用的时候,做插入订单之间。不需要重新编号。

最好的解决方案是 双向链表。O (1)用于除索引以外的所有操作。但是,除了您想要的项上的 where 子句之外,没有任何东西可以快速索引 SQL。

0、10、20种类型失败。序列列失败。浮点序列列在组移动时失败。

双向链表是相同的操作,包括添加、删除、删除群组、添加群组、移动群组。单链表也可以。在我看来,使用 SQL 时双向链接更好。单链表要求您拥有整个列表。

好了,这里是我的解决方案,使编程这个更容易为任何人发生沿着这个线程。诀窍在于能够在一次更新中更新插入/删除操作之上或之下的所有订单索引。

在表中使用 SQL 查询支持的数字(整数)列

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

删除 orderindex 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,因此使用 it 作为虚拟项,以避免出现含糊不清的条目。

在3处插入:

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

当我使用 Hibernate,并且需要保存 @OneToMany的顺序时,我使用的是 Map而不是 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 }));

在这个 Java 示例中,positionRuleAction的 Integer 属性,因此顺序以这种方式持久化。我想在 C # 中这看起来会非常相似。

我是这样解出 务实的:

  1. 顺序在 UI 中定义。

  2. 后端获取一个 POST 请求,该请求包含列表中每个项的 ID 和对应的 Position。

  3. 我开始一个交易,并更新每个 ID 的位置。

成交。

因此,订购是昂贵的,但阅读订购列表是非常便宜的。