Может ли порядок итерации набора записей ADODB.изменяться во время итерации

#c# #database #vb.net

Вопрос:

У меня есть следующий фрагмент устаревшего кода, который мне нужно переписать на c#:

 Dim dif As Integer
Dim rstTemp As ADODB.Recordset
Set rstTemp = database.OpenRecordset("select * from TABLE order by VALUE desc")
Set dif = <input>
Do Until dif = 0
    rstTemp.Fields("VALUE") = rstTemp.Fields("VALUE") - 1
    rstTemp.Update
    rstTemp.MoveNext
    dif = dif - 1
Loop
 

Нет проверки для rstTemp.EOF, поэтому мне кажется, что обновление изменяет порядок итераций во время итерации и всегда переходит к первому?
Разница может быть намного больше, чем количество записей, поэтому она должна как-то зацикливаться.
Будет ли этот код C# эквивалентен?

 int dif = <input>;
while (dif != 0)
{
    var record = _context.TABLE.OrderByDescending(x => x.VALUE).First();
    record.VALUE--;
    _context.SaveChanges();
    dif--;
}
 

Ответ №1:

Этот код очень разные; в старом (в VB6?) версия запросе раз; в C# версии он может запрос сразу (если _context пятна какие-то кэширование, оптимизация), но это может (и скорее всего будет) запрос один раз для каждого цикла итерации — и это почти всегда получаю одну и ту же строку каждый раз, вместо того, чтобы принимать последовательные записи из запроса. Как минимум, вы могли бы попробовать:

 int dif = <input>;
foreach (var record in _context.TABLE.OrderByDescending(x => x.VALUE).Take(dif))
{
    record.VALUE--;
    _context.SaveChanges();
    if (--dif == 0) break;
}
 

Однако из-за того, как работает пакетирование, возможно, имеет смысл просто сделать один SaveChanges() в конце.

Что касается вашего фактического вопроса, который, я думаю, связан с взаимодействием ORDER BY и текущими обновлениями; это будет во многом зависеть от уровня изоляции и других настроек; я могу только сказать: «Вероятно, нет, но … может быть»! Возможно, настоящая хитрость здесь в том, чтобы понять, чего пытался достичь исходный код (а не как он это сделал). В частности, это похоже на то, что может быть полностью выгружено на стороне сервера, даже не требуя извлечения записей по сети — с помощью соответствующим образом созданного SQL. Это также даст вам гораздо лучшую атомарность без больших накладных расходов в оба конца, приводящих к длительной транзакции.

Комментарии:

1. К сожалению, клиент будет жаловаться, если он получит другие результаты (даже если старый результат будет математически доказан неверным), поэтому я должен придерживаться «как работал старый код», а не «чего нужно было достичь». Тот факт, что нет проверки на restTemp.EOF, несколько убеждает меня в том, что порядок меняется, но тогда, если это не всегда первый лучший результат, как бы он подскочил?