我试图找出使表格可以任意排序的最佳方法。我的意思是用户可以改变表格的排序顺序而与数据无关。
为了适应这种情况,我在名为Rank
的表中添加了一个新列,该列应该用于排序。
我写了这个函数来改变给定实体的等级
public void ChangeRank(int id, int rank)
{
_dbSet.Find(id).Rank = rank;
// adjust ranks
var index = rank + 1;
foreach (var entity in _dbSet.Where(x => x.Rank >= rank && x.Id != id).OrderBy(x => x.Rank))
entity.Rank = index++;
_context.SaveChanges();
}
我相信,如果我错了,请纠正我,将foreach循环翻译成单个sql语句,这是我希望做的 - 性能。我很确定使用row_number()
可以在原始sql中进行,但我想将其保留为LINQ查询。
我如何优化排名更新?
有没有更好的方法来实现任意排序?
答案 0 :(得分:0)
我认为Find
比First
慢了许多倍。其次,逻辑可以简化,因此您不需要排序:
var row = _dbSet.First(x => x.Id == id);
var oldRank = row.Rank;
if(oldRank == newRank)
return;
if(newRank > oldRank)
{
foreach (var entity in _dbSet.Where(x => x.Rank > oldRank))
{
if(entity.Rank > newRank)
entity.Rank++;
else
entity.Rank--;
}
} else
{
// think the logic yourself.
}
row.Rank = newRank;
如果你对row.Rank编制索引,它可能会非常好。您可能还希望确保Row.Rank
具有唯一约束,或者您应该考虑事务。
如果你使用大规模系统,你可能需要在SQL中实现某种树结构,这样更新元素的等级就是O(logn)操作(超快) - Database Structure for Tree Data Structure
关于实体框架:不,EF不适合这类问题。您应该检查此threa Batch update/delete EF5并查看是否可以找到有用的内容。事实上,EF根本没有与批量记录表现良好。
答案 1 :(得分:0)
我会避免更新多个实体。
将Rank
设为double
,无论何时需要ChangeRank,请将其设置为接下来两个记录之间的值。例如,如果您想将实体移动得更低:
public void MoveDown(int id)
{
var entity = _dbSet.Find(id);
var nextTwo = _dbSet.Where(x => x.Rank > entity.Rank)
.OrderBy(x => x.Rank)
.Select(x => x.Rank)
.Take(2).ToList();
if (nextTwo.Count == 2)
{
entity.Rank = (nextTwo[0] + nextTwo[1]) / 2;
}
// if entity is second last
else if (nextTwo.Count == 1)
{
entity.Rank = nextTwo[0] + 1;
}
_context.SaveChanges();
}
向下移动ID 1的示例结果
Before
ID Rank
1 1
2 2
3 3
After
ID Rank
1 2.5
2 2
3 3
如果您想将实体设置到某个位置,可以使用类似的方法,但想法是仅修改一个实体