【问题标题】:Update statement to keep tracking of SortOrder in database更新语句以跟踪数据库中的 SortOrder
【发布时间】:2016-12-29 07:33:42
【问题描述】:

我在屏幕上有一个产品图片列表。当用户拖放图像时,我可以访问 oldIndex 和 newIndex。

假设我有以下几点:
产品1[索引:0]
产品2[索引:1]
产品3[索引:2]
产品4[索引:3]
产品5[索引:4]
Product6[索引:5]

而用户决定将 Product2 放在 Product4 之前

我想弄清楚我的数据库更新语句是什么。我正在阅读另一篇文章,看到有人说您应该更新 >= newIndex 的所有产品的 SortOrder 字段,然后将新产品更新到 newIndex 中。

在我看来,这件事有些不对劲,这会给我留下以下信息:
产品1[索引:0]
产品2[索引:2]
产品3[索引:3]
产品4[索引:4]
产品5[索引:5]
Product6[索引:6]

我真的在努力实现这一点,让我的索引保持完美的顺序,没有间隙。有什么建议吗?

【问题讨论】:

  • 我以前用实体框架做过这种事情。是否需要在 SQL 中?
  • @BlakeRivell,请指定您使用哪个 SQL 服务器?
  • @dans 是的,我正在使用实体框架,我只是假设有人用 SQL 术语向我描述最容易。我正在使用 kendo UI 排序小部件,它允许我在列表视图中拖放图像,并且 onChange 可以访问已移动项目的 oldIndex 和 newIndex。我的计划是此时调用 ajax 来更新所有记录的排序顺序。

标签: c# sql sorting


【解决方案1】:

所以我写了一个 void 来处理繁重的工作。由于我需要对多种类型的实体执行此操作,所有这些实体都有一个SortOrder 列,因此我创建了一个名为ISortable 的接口,其中包含一个SortOrder 列。如果您只是使用一个 db 表执行此操作,则可以将 ISortable 的任何实例替换为您的实体名称。

在这个空白之外需要发生的事情是:

从数据库中获取您的项目并将其旧排序顺序存储在变量 (oldSortOrder) 中,然后设置项目的新排序顺序 (newSortOrder),然后将变量设置为所有其他项目不是您刚刚更新的那个 (list)。这也说明了从数据库中删除的项目,只需在您的 ajax 调用中将 newSortOrder 设置为 0

WebApi 方法:

// Code is activated when accessed via http PUT
public void PutItem(int itemId, int newSortOrder)
{
    // using makes sure Context is disposed of properly
    using (var Context = new MyDbContext())
    {
        var oldSortOrder = 0;

        IEnumerable<ISortable> itemsToReorder = null;

        // Get moved item from database
        var item = Context.Items.FirstOrDefault(x => x.ItemId == itemId);

        // Before we set the new sort order, set a variable to the
        // old one. This will be used to reorder the other items.
        oldSortOrder = item.SortOrder;

        // Get all items except the one we grabbed above.
        itemsToReorder = Context.Items.Where(x => x.ItemId != itemId);

        // Delete if the item is set for deletion (newSortOrder = 0)
        if (newSortOrder == 0)
        {
            Context.Items.Remove(item);
        }
        // Otherwise, set the new sort order.
        else
        {
            item.SortOrder = newSortOrder;
        }

        // Pass other items into reordering logic.
        ReOrder(itemsToReorder, oldSortOrder, newSortOrder);

        // Save all those changes back to the database
        Context.SaveChanges();
    }
}

重新排序无效:

public static void ReOrder(IEnumerable<ISortable> list, 
    int oldSortOrder, 
    int newSortOrder)
{
    IEnumerable<ISortable> itemsToReorder;

    // Pare down the items to just those that will be effected by the move.
    // New sort order of 0 means the item has been deleted.
    if (newSortOrder == 0)
    {
        itemsToReorder = list.Where(x => x.SortOrder > oldSortOrder);
    }
    else
    {
        // This is just a long inline if statement. Applies Where()
        // conditions depending on the old and new sort variables.
        itemsToReorder = list.Where(x => (oldSortOrder < newSortOrder
            ? x.SortOrder <= newSortOrder &&
            x.SortOrder > oldSortOrder
            : x.SortOrder >= newSortOrder &&
            x.SortOrder < oldSortOrder));
    }

    foreach (var i in itemsToReorder)
    {
        // Original item was moved down
        if (newSortOrder != 0 && oldSortOrder < newSortOrder)
        {
            i.SortOrder -= 1;
        }
        // Original item was moved up
        else if (newSortOrder != 0 && oldSortOrder > newSortOrder)
        {
            i.SortOrder += 1;
        } // Original item was removed.
        else
        {
            i.SortOrder -= 1;
        }
    }
}

如果您需要澄清,请告诉我。我几乎可以肯定我没有充分解释一切。

【讨论】:

  • 非常感谢您的回答。所以我猜我的 Web API 方法只需要两个参数。正在移动的实体的 id 以及它的新 sortIndex。当我去删除一条记录时会发生什么,我之后运行相同的逻辑吗?
  • 哦。我没有包括删除部分。我会更新的。你基本上发送itemIdnewSortOrder = 0
  • 我完全实现了这个逻辑,但由于某种原因,我在重新排序期间不断重复。例如,其中两个的 SortOrder 为 6。您的排序顺序是从零开始的吗?我正在基于零,因为我使用的剑道 ui 控件将第一个视为索引 0。此外,我相信我将不得不使用 sortOrder -1 进行删除,因为从技术上讲,0 是第一项,对吗?
  • 是的,它是基于 1 的。您必须进行一些调整才能使其适用于基于 0 的情况。
  • 我最终把这一切都解决了。对于删除,我只是能够查找 SortOrder 大于被删除项的所有项目,然后将它们的 SortOrder 减去 1。您对初始保存有什么建议,我如何确保添加的第一批项目有例如,从 1 到 5 的正确排序顺序。我的问题是我使用的异步上传技术分别对 5 个文件中的每一个发出请求,因此我无法在初始保存期间设置初始排序顺序。
【解决方案2】:
IF OBJECT_ID('tempdb..#Product') IS NOT NULL
    DROP TABLE #Product

CREATE TABLE #Product(
    Name VARCHAR(100) NOT NULL
    ,SortOrder INT NOT NULL
)

INSERT INTO #Product (Name, SortOrder)
VALUES 
 ('Product1', 0)
,('Product2', 1)
,('Product3', 2)
,('Product4', 3)
,('Product5', 4)
,('Product6', 5)

DECLARE 
    @NewIndex INT
    ,@OldIndex INT

SET @OldIndex = 4   --'Product5'
SET @NewIndex = 2   -- After 'Product2'

IF @NewIndex < @OldIndex    -- Move UP
    UPDATE #Product
        SET SortOrder = CASE 
                        WHEN SortOrder = @OldIndex THEN @NewIndex 
                        ELSE SortOrder + 1
                        END
    WHERE SortOrder BETWEEN @NewIndex AND @OldIndex;
ELSE                        -- Move DOwn
    UPDATE #Product
        SET SortOrder = CASE 
                        WHEN SortOrder = @OldIndex THEN @NewIndex 
                        ELSE SortOrder - 1
                        END
    WHERE SortOrder BETWEEN @OldIndex AND @NewIndex;

SELECT * FROM #Product ORDER BY SortOrder 

【讨论】:

    猜你喜欢
    • 2021-07-11
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    相关资源
    最近更新 更多