支持使用jquery对html表行重新排序以及使SQL后端快速的最佳方法?
我有一个asp.net-mvc网站,我有一个html数据表,其中一列是排名,表示该行的优先级(每行代表一个请求)。我允许人们用一个新的数字编辑一行中的数据,但它实际上不会影响任何其他行(例如,没有什么可以阻止人们输入另一行中存在的alraedy值) 我正在寻找一个解决方案,有一个更有效的前端和一个快速的后端。我会逐一列出:支持使用jquery对html表行重新排序以及使SQL后端快速的最佳方法?,jquery,sql-server,asp.net-mvc,Jquery,Sql Server,Asp.net Mvc,我有一个asp.net-mvc网站,我有一个html数据表,其中一列是排名,表示该行的优先级(每行代表一个请求)。我允许人们用一个新的数字编辑一行中的数据,但它实际上不会影响任何其他行(例如,没有什么可以阻止人们输入另一行中存在的alraedy值) 我正在寻找一个解决方案,有一个更有效的前端和一个快速的后端。我会逐一列出: 前端: 我想要一些功能,可以上下拖放行,或者单击上/下箭头,或者当我在一行中输入排名值时,它会更新所有其他行的排名。我基本上不希望用户在有排名为#1的新条目时必须更新每一行(
我的相关问题是,当我更新后端时,我正试图找出如何避免这一非常缓慢的操作。如果我的数据库表中有一个秩字段,并且有人将某个项更新为第一,我实际上必须每隔一行运行一次更新查询,以将该值更改为现有值+1。是否存在一些问题更有效地执行此操作的模式?以下是有关后端的两个想法 使后端中的值类似于: 1–排名#1 100–排名第2 200–排名第3 等等 这将允许您在其他两行之间添加值时更新最小行数 例如,如果要在秩#3处插入一个值,只需输入值150即可 向用户显示数据时,不显示数据库中的实际值,而是使用函数以用户友好的方式显示数据 当你想在第1位添加一些东西时,你只需输入一个比现有第一位小一些的值就可以了。不管实际值最终看起来是不是-250,只要顺序正确,行数函数都会处理显示 你偶尔需要做的就是重新排序值,以便在两者之间有足够的空间。用于前端查看功能。它通常应用于
或元素,但如果需要,也可以通过谷歌快速搜索将其调整为
元素
一次插入级联到多个更新中的后端问题可以通过将其视为链表来解决
我假设您将数据存储为:
Rank | Key
1 | Zebra
2 | Pig
3 | Pony
因此,插入新行可能需要更新所有现有行:
Rank | Key
1 | Penguin * Inserted
2 | Zebra * Updated
3 | Pig * Updated
4 | Pony * Updated
相反,通过将它们与表中的另一行关联来存储它们的顺序
Key | ComesAfter
Zebra | null
Pig | Zebra
Pony | Pig
因此,插入新行最多需要一次更新
Key | ComesAfter
Penguin | null * Inserted
Zebra | Penguin * Updated
Pig | Zebra * Unchanged
Pony | Pig * Unchanged
当然,您可以使用ID进行此操作
但是
<>你可能会过早地优化;可能是一些简单的SQL工作即使在发布许多更新时也证明是非常有效的。
Key | Rank
Zebra | 3
Pig | 1
Pony | 2
请注意,该值在这里充当自然键,它还可以有一个ID(与秩不同)
要将新行添加为排名1,您需要执行以下操作:
begin tran
insert values ('Penguin', 1)
update table set Rank = Rank + 1 where Rank >= 1
commit
添加索引和可能的分区(取决于表的大小)将提供极大的性能改进——唯一的折衷办法是偶尔进行数据库管理
这里的主要问题是你最喜欢哪个方面:快速读取、快速写入或简单设计?你可以有三个方面中的两个:)扩展@Dwoolk的答案,你可以使用浮点数进行排序。然后,您应该始终(至少在很长一段时间内)能够在两个现有值之间找到新值。对于上下移动项目,您可以使用。最简单的解决方案是在所有项目中添加一个称为score的浮点数,可能是一个double。当顺序可能改变时,这是保持一组元素有序的更有效的技术。从数据库到表示层的所有层中都必须保留Thid分数。当您需要将一个元素放在两个其他元素之间时,只需将其float设置为两个元素的平均年龄,这样您就可以确定它位于两个元素之间
从数据库中检索按分数排序的所有项目
使用两个分数为0的伪项(未渲染,也未插入数据库,但纯粹是虚拟项)启动算法。和1。所有“真实”项目将插入它们之间。因此,您的第一个元素将得到0.5分,依此类推
您必须在DB中存储两个分数之间的最小距离。当这个数字变得太小并且接近使用double可能获得的最小精度时,您必须通过分配分数来重新组织表格,以便两个连续元素之间的所有分数距离相同且等于1/(项目数)
如果您需要向用户显示“经典排名”1、2、3。。。。您可以在呈现页面之前以及每次用户修改之后立即在网页中创建它。
更新所有列组的成本等于屏幕上显示的项目。这不是一个大问题,这不会导致性能下降,因为浏览器必须重新渲染屏幕上的所有元素,其成本高于在屏幕上重新写入所有列的成本…重要…如果您有虚拟滚动或分页…列组重写只涉及屏幕上的活动元素,因为列组的唯一目的是向用户显示
UDPATE table SET rank=rank+1 WHERE rank >= {begin value} AND rank <= {end value};
UDPATE table SET rank=rank+1 WHERE listID = {given list ID} AND rank >= {begin value} AND rank <= {end value};
angular.module("listApp", []).
controller("listController", function($scope) {
var sortByKey = function(arr, key) {
arr.sort(function(a, b) {
if (a[key] > b[key]) {
return -1;
} else if (b[key] > a[key]) {
return 1;
} else {
return 0;
}
});
};
$scope.items = [{id: 1111, name: "Item 1", score:0.2},
{id: 3333, name: "Item 2", score:0.5},
{id: 5555, name: "Item 3", score:0.7}];
sortByKey($scope.items, "score");
}).
directive("sortable", function() {
return function(scope, element) {
var startIndex = null;
var stopIndex = null;
var averageOfNeighbors = function(items, index) {
var beforeScore = index === 0 ? 1 : items[index -1].score;
var afterScore = index === items.length - 1 ? 0 : items[index + 1].score;
return (beforeScore + afterScore) / 2;
}
element.sortable( {
start: function(e, ui) {
startIndex = ui.item[0].sectionRowIndex;
},
stop: function(e, ui) {
stopIndex = ui.item[0].sectionRowIndex;
if (stopIndex !== startIndex) {
var toMove = scope.items.splice(startIndex, 1)[0];
scope.items.splice(stopIndex, 0, toMove);
toMove.score = averageOfNeighbors(scope.items, stopIndex);
console.log("Set item(" + toMove.id + ").score to " + toMove.score);
scope.$apply();
}
}
});
}
})
<tbody sortable>
<tr ng-repeat="item in items">
<td>{{item.name}}</td>
<td>{{$index + 1}}</td>
<td>{{item.score}}</td>
</tr>
</tbody>