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

时间:2014-12-18 18:07:57

标签: c# sql-server linq entity-framework

我试图找出使表格可以任意排序的最佳方法。我的意思是用户可以改变表格的排序顺序而与数据无关。 为了适应这种情况,我在名为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查询。

我如何优化排名更新?

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

2 个答案:

答案 0 :(得分:0)

我认为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编制索引,它可能会非常好。您可能还希望确保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

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