#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, несколько убеждает меня в том, что порядок меняется, но тогда, если это не всегда первый лучший результат, как бы он подскочил?