#c# #sql #sql-server
Вопрос:
У меня есть SQL-запрос, который я хочу проверить, если что-то вернется. Цель состоит в том, чтобы ничего не вернуть, и я хочу повторить попытку в течение 15 секунд, если что-то будет возвращено. Однако мне трудно заставить этот цикл работать должным образом. Может ли кто-нибудь предложить исправить этот код? Он переходит к «SQL-таблице хорошо!» после 2 попыток, хотя запрос должен был что-то вернуть.
//SqlDataReader readerPromo = promoTablecmd.ExecuteReader();
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
//Loop so that if less than 10 seconds, keep retrying SQL cmd above.
while (true)
{
double elapsedTime = stopwatch.ElapsedMilliseconds;
SqlDataReader readerPromo = promoTablecmd.ExecuteReader();
// If query returned something
if (readerPromo.Read())
{
if (elapsedTime > 15000)
{
Console.WriteLine("Error found!");
break;
}
else
{
Console.WriteLine("Found descrepency in SQL table retrying again for 10 seconds...");
System.Threading.Thread.Sleep(1000);
continue;
}
}
else {
Console.WriteLine("SQL table good!");
}
}
Комментарии:
1. Переместитесь
execute reader
в петлю2. Вы должны повторно выполнять запрос каждый раз, когда хотите проверить. Новые результаты не передаются автоматически в открытый читатель. Таким образом, первая строка кода должна находиться внутри цикла, так как вы хотите выполнять ее на каждой итерации цикла.
3. Я попробовал, однако он продолжает выдавать мне, что с этой командой уже связан открытый читатель данных, который сначала должен быть закрыт. Я попытался установить «MultipleActiveResultSets=true» в моем соединении, но это не сработало. Пожалуйста, смотрите отредактированный код.
4. Правильный. Вы должны использовать
using
блок для своего считывателя, чтобы закрыть считыватель и, возможно, базовое соединение, в зависимости от поведения, указанного при открытии считывателя. Вы можете оставить соединение открытым, хотя я бы не рекомендовал это делать, если это длительный процесс, особенно если ado.net для вас реализован пул соединений, поэтому открытие нового управляемого соединения обходится относительно дешево.5.
promoTablecmd.ExecuteScalar()
это полностью избавило бы от необходимости в читателе. Все, что вы хотите знать здесь, это есть ли хотя бы один результат, вам не нужен читатель
Ответ №1:
Использование асинхронности здесь более корректно. Это должно сработать:
[Test]
public async Task Repro()
{
var sqlCmd = new SqlCommand();//mock
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(15));//timeout after 15 seconds
await WaitEndOfDataAsync(sqlCmd, cts.Token, TimeSpan.FromSeconds(1));//setting check interval
}
private static async Task WaitEndOfDataAsync(SqlCommand cmd, CancellationToken cancellationToken, TimeSpan checkInterval)
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
using(var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false))
{
var hasData = await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
await reader.CloseAsync().ConfigureAwait(false);
if (!hasData)
return;
}
cancellationToken.ThrowIfCancellationRequested();
await Task.Delay(checkInterval, cancellationToken);
}
}
Он будет перебирать данные, и если истечет время ожидания — вызовет исключение OperationCancelledException.