用于更改实体排名顺序的高效 linq 查询



我正在尝试找出使表格任意排序的最佳方法。我的意思是用户可以更改表的排序顺序,而与数据无关。为了适应这一点,我在表中添加了一个名为 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查询。

如何优化排名更新?

有没有更好的方法来实现任意排序?

我会避免更新多个实体。

Rank设置为double,每当需要更改排名时,请将其设置为接下来两条记录之间的值。例如,如果您想将实体向下移动:

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

如果要将实体设置为某个位置,则可以使用类似的方法,但想法是仅修改一个实体

我认为FindFirst慢很多倍。其次,逻辑可以简化,所以你不需要排序:

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具有唯一的约束,或者您应该考虑事务。

如果您使用的是大型系统,则可能需要在SQL中实现某种树结构,以便更新元素的秩是O(logn(操作(超快( - 树数据结构的数据库结构

关于实体框架:不,EF 不适用于此类问题。您应该检查此批处理更新/删除EF5,看看是否可以找到有用的内容。事实是,EF 在批量记录中的表现并不好。

相关内容

  • 没有找到相关文章

最新更新