【问题标题】:Best way to save a ordered List to the Database while keeping the ordering在保持排序的同时将有序列表保存到数据库的最佳方法
【发布时间】:2017-07-01 04:15:13
【问题描述】:

我想知道是否有人能很好地解决我在过去几年中多次遇到的问题。

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

显而易见的方法是简单地插入一些 OrderField,我会将数字 0 分配给 N 并以这种方式排序。

但是这样做会使重新排序变得更加困难,而且我不知何故觉得这个解决方案有点脆弱,总有一天会回到我身边。

(我将 C# 3,5 与 NHibernate 和 SQL Server 2005 一起使用)

谢谢

【问题讨论】:

    标签: c# database nhibernate sql-order-by


    【解决方案1】:

    好的,这是我的解决方案,可以让遇到此线程的任何人都更轻松地进行编程。诀窍是能够在一次更新中更新插入/删除上方或下方的所有订单索引。

    在表中使用数字(整数)列,由 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)
    

    【讨论】:

      【解决方案2】:

      最佳解决方案是Doubly Linked list。 O(1) 对于除索引之外的所有操作。除了你想要的项目的 where 子句之外,没有什么可以快速索引 SQL。

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

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

      【讨论】:

      • 这是最好的解决方案恕我直言。例如,我的 Netflix 队列中有 300 多部电影。如果我将一个项目从位置 297 移动到顶部,netflix 就不必进行 300 次更新。最多只有 3 次更新
      • 获得前 50 个项目的最佳方法是什么?是否需要一一阅读,还是有什么神奇的 sql 解决方案?
      • @akn 这可以使用递归查询,然后将行数限制为 50 以获得前 50 行。
      • 我不明白双向链表如何帮助数据库中的“排序”和“将订单序列保存为浮点数或整数”?双链表操作不是只发生在应用程序端吗?您如何使用列表更新数据库?您仍然需要编写一个算法来将有序列保存在数据库中。除非我错过了什么。
      • @ANewGuyInTown 他说实现你的行数据结构,就好像它是一个双向链表。条目将引用列表层次结构中的兄弟姐妹之前和之后。
      【解决方案3】:

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

      【讨论】:

      • 不知怎的,我觉得保持这个顺序可能会在未来引起头疼。所以我问了,也许有人找到了更好的解决方案。
      • 别担心 - 没有比使用排序列更好的方法了。至于未来的头疼问题……不要试图针对你不知道的用例进行优化。
      • 由于您通常获取整个购物车以进行展示,因此重新编号整个购物车似乎并不是问题
      • 我同意,只是感觉太脆弱了。但是在我意识到我可以将整个排序逻辑放在存储库中并且整个事情对我的业务代码是透明的之后,它可以完美地工作。谢谢你的建议。
      【解决方案4】:

      使用链表实现怎么样?有一列将保存下一个项目的值(订单号)。我认为这是迄今为止在两者之间插入订单时最容易使用的。无需重新编号。

      【讨论】:

        【解决方案5】:

        不幸的是,没有灵丹妙药。如果没有 order by 子句,您将无法保证任何 SELECT 语句的顺序。您需要添加列并围绕它进行编程。

        我不知道我是否建议在订单序列中添加间隙,具体取决于您的列表大小和网站上的点击量,您可能会因为处理逻辑的开销而获得很少的收益(您' d 仍然需要满足所有间隙都用完的场合)。我会仔细看看这会给你带来什么好处。

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

        【讨论】:

        • 由于您通常会获取整个购物车以进行展示,因此重新编号整个购物车似乎并不是问题。
        • 如果列表恰好足够大,以至于您不想在重新排序时更新每一行,您可以使用浮点 DisplayOrder 列。我没有尝试过,但这只是一个想法......
        【解决方案6】:

        我根本不推荐 A、AA、B、BA、BB 方法。确定层次结构涉及很多额外的处理,并且在两者之间插入条目一点也不好玩。

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

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

        一旦你为它编写了一个小库,那将是小菜一碟。

        【讨论】:

          【解决方案7】:

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

          如果您发现由于插入和更新性能不佳而导致此限制,则可以使用 varchar 字段而不是整数。这允许在插入时具有相当高的精度。例如,要在项目“A”和“B”之间插入,您可以插入订购为“AA”的项目。不过,这对于购物车来说几乎可以肯定是矫枉过正。

          【讨论】:

          • 在您的 varchar 字段排序中,Z 之后会发生什么?
          【解决方案8】:

          在购物车项目之上的抽象级别上,假设 CartOrder(与 Ca​​rtItem 有 1-n),您可以维护一个名为 itemOrder 的字段,它可能只是一个逗号分隔的 cartItem 记录相关的 id(PK) 列表。它将在应用程序层,您需要对其进行解析并相应地安排您的项目模型。这种方法的最大优点是在订单重新洗牌的情况下,可能不会对单个对象进行更改,但是由于订单作为索引字段保留在订单项目表行中,因此您必须为每个对象发出更新命令行更新其索引字段。 请让我知道您对这种方法的批评,我很想知道这可能会以何种方式失败。

          【讨论】:

            【解决方案9】:

            务实地这样解决了它:

            1. 订单在 UI 中定义。

            2. 后端获取一个 POST 请求,其中包含列表中每个项目的 ID 和相应的位置。

            3. 我开始一个事务并更新每个 ID 的位置。

            完成。

            所以订购很昂贵,但阅读订购列表却超级便宜。

            【讨论】:

              【解决方案10】:

              我建议在订单号中保留空白,因此不要使用 1、2、3 等,而是使用 10、20、30...而不是在那时重新排序所有内容。

              【讨论】:

              • 只有用 BASIC 编写系统才行 ;-)
              • 说真的,但是,这种方法只会推迟实际进行排序的需要,然后您的代码中有两个不同的功能位。如果您可能不得不在某个时候处理某种排序,为什么不从一开始就做,并降低复杂程度?
              【解决方案11】:

              好吧,我想说的简短答案是:

              在 cartcontents 表中创建一个 autoidentity 的主键,然后以正确的自上而下的顺序插入行。然后通过按主键自动标识列的顺序从表中选择,将为您提供相同的列表。通过这样做,您必须删除所有项目并重新插入,以防购物车内容发生变化。 (但这仍然是一种非常干净的方式)如果这不可行,那么就像其他人建议的那样使用订单列。

              【讨论】:

                【解决方案12】:

                当我使用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 的整数属性,因此顺序以这种方式保持不变。我猜在 C# 中这看起来很相似。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-11-30
                  • 2014-03-08
                  • 2016-09-30
                  • 2020-12-20
                  • 2012-06-19
                  • 2014-07-13
                  • 2018-10-18
                  相关资源
                  最近更新 更多