我想知道是否有人能够很好地解决我在过去几年遇到过的问题。
我有一个购物车,我的客户明确要求它的订单很重要。所以我需要将订单持久保存到DB。
显而易见的方法是简单地插入一些OrderField,我将数字0分配给N并按此方式排序。
但这样做会使重新排序变得更加困难,而且我觉得这个解决方案有点脆弱,有一天会回到我身边。
(我在NHibernate和SQL Server 2005中使用C#3,5)
谢谢
答案 0 :(得分:47)
好的,这是我的解决方案,使这个线程中的任何人都可以更轻松地编程。诀窍是能够在一次更新中更新插入/删除之上或之下的所有订单索引。
在表中使用数字(整数)列,受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,所以使用它作为假人以避免出现含糊不清的项目。
要插入3:
UPDATE myitems SET orderindex = (orderindex + 1) WHERE orderindex > 2;
INSERT INTO myitems (Myitem,orderindex) values ("MytxtitemHere",3)
答案 1 :(得分:31)
最佳解决方案是Doubly Linked list。 O(1)用于除索引之外的所有操作。除了你想要的项目的where子句之外,没有什么能快速索引SQL。
0,10,20类型失败。序列列失败。组移动时浮动序列列失败。
双向链接列表与添加,删除,组删除,组添加,组移动相同。单链表也可以。在我看来,双链接更好用SQL。单链表要求您拥有整个列表。
答案 2 :(得分:24)
FWIW,我认为您建议的方式(即将订单提交到数据库)对您的问题来说并不是一个糟糕的解决方案。我也认为这可能是最安全/最可靠的方式。
答案 3 :(得分:10)
如何使用链接列表实现?有一列将保存下一个项目的值(订单号)。我认为这是目前在插入订单时最容易使用的。无需重新编号。
答案 4 :(得分:5)
不幸的是,这没有灵丹妙药。您无法保证任何SELECT
语句的顺序,而不包含order by子句。您需要在其周围添加列和程序。
我不知道我建议在订单序列中添加间隙,具体取决于列表的大小和网站上的点击次数,您可能无法获得处理逻辑的空头(你' d仍然需要迎合所有差距已经用完的场合)。我会仔细看看在你的情况下这会给你带来什么好处。
对不起,我不能提供更好的东西,希望这有帮助。
答案 5 :(得分:4)
我根本不推荐A,AA,B,BA,BB方法。确定层次结构需要进行大量的额外处理,并且在两者之间插入条目根本不是很有趣。
只需添加一个OrderField,整数。不要使用间隙,因为您必须在下一个中间插入处使用非标准“步骤”,或者您必须先重新同步列表,然后添加新条目。
有0 ... N很容易重新排序,如果你可以使用SQL之外的Array方法或List方法整个集合重新排序,那么更新每个条目,或者你可以找出你的位置因此,在每个条目之后或之前插入,以及+1或-1。
一旦你为它写了一个小图书馆,它就会变得轻而易举。
答案 6 :(得分:1)
我只想插入一个订单字段。这是最简单的方法。如果客户可以重新排序字段,或者您需要在中间插入,则只需重写该批次中所有项目的订单字段。
如果由于插入和更新的性能不佳而在线下发现这种限制,则可以使用varchar字段而不是整数。这允许在插入时具有相当高的精度。例如,要在项目“A”和“B”之间插入,您可以插入按“AA”排序的项目。对于购物车来说,这几乎肯定是过度杀伤。
答案 7 :(得分:1)
在购物车上方的抽象层次上,让我们说CartOrder(具有1-n的CartItem)你可以维护一个名为itemOrder的字段,它可以只是一个逗号分隔的cartItem记录相关的id(PK)列表。它将在应用程序层,您需要解析它并相应地安排您的项目模型。这种方法的一大优点是在订单重组的情况下,单个对象可能没有变化,但由于订单在订单项表行中保持为索引字段,因此您必须为每个对象发出更新命令。行更新其索引字段。 请让我知道你对这种方法的批评,我很想知道这可能会失败的方式。
答案 8 :(得分:1)
我解决了实用这样:
订单在界面中定义。
后端获取一个POST请求,其中包含ID和列表中每个项目的相应位置。
我开始一个交易并更新每个ID的位置。
完成。强>
因此订购费用昂贵,但阅读有序清单非常便宜。
答案 9 :(得分:0)
我建议在订单编号中保留间隙,所以不要使用1,2,3等,而是使用10,20,30 ......如果你只需要插入一个项目,你可以把它放在15,而不是而不是重新安排那一切。
答案 10 :(得分:0)
好吧,我会说简短的回答是:
在cartcontents表中创建自动同一性的主键,然后以正确的自上而下顺序插入行。然后通过主键自动列表从表中选择顺序将给出相同的列表。通过执行此操作,您必须删除所有项目,然后重新插入,以便更改购物车内容。 (但这仍然是一种非常干净的方式)如果这不可行,那么按照其他人建议的顺序栏进行操作。
答案 11 :(得分:-1)
当我使用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示例中,position
是RuleAction
的Integer属性,因此顺序保持不变。我想在C#中这看起来很相似。