Я выполняю хранимую процедуру, и внутри хранимой процедуры есть цикл WHILE. Каждый раз, когда итерация происходит в цикле WHILE, она выводит таблицу (показывающую ее прогресс). Я хотел бы захватить эту таблицу и прочитать ее в.NET (используя драйвер.NET SQLClient). Я хотел бы иметь возможность прочитать эту таблицу прогресса, как создается таблица (например, в SSMS) и NOT, когда хранимая процедура завершена.
PS: Мне все равно, какой язык.NET вам нравится - решение или идеи на любом языке были бы весьма признательны.
Думаю, я придумал способ сделать это. Я начал с создания небольшой локальной базы данных с одной таблицей, которая называется Table1, которая имеет текстовый столбец с именем status. Я также создал StoredProcedure под названием StoredProcedure1. Это выглядит так:
CREATE PROCEDURE dbo.StoredProcedure1
/*
(
@parameter1 int = 5,
@parameter2 datatype OUTPUT
)
*/ AS
declare @setCount int
declare @result table (cnt int)
set @setCount = 0
insert into Table1 (status) VALUES ('Starting');
while @setCount < 5
begin
WAITFOR DELAY '00:00:03';
insert into @result (cnt)
select @setCount
set @setCount = @setCount + 1;
update Table1 set status='Iteration ' + cast(@setCount as varchar);
end
RETURN
Хранимая процедура просто вставляет начальное значение статуса в таблицу1, а затем циклически проходит через 5 итераций, задерживая три секунды для каждой итерации, чтобы имитировать длительный процесс. В конце каждой итерации поле статуса обновляется, чтобы отразить следующую итерацию.
Затем я создал проект WindowsForms с единственной формой, которая имеет одну метку. Я создал частный метод для выполнения хранимой процедуры как долгого процесса.
Private Sub LongRunningProcess()
Dim _conn As New SqlClient.SqlConnection("Data Source=.\sqlexpress;Initial Catalog=MARS_ProcTest;Integrated Security=True;MultipleActiveResultSets=True;")
Dim cmd As New SqlClient.SqlCommand("exec StoredProcedure1", _conn)
Dim ds As New DataSet
_conn.Open()
cmd.ExecuteNonQuery()
_conn.Close()
End Sub
Затем я создал другой метод, который будет проверять статус в таблице1 до завершения хранимой процедуры.
Private Sub StatusChecker()
Dim _conn As New SqlClient.SqlConnection("Data Source=.\sqlexpress;Initial Catalog=MARS_ProcTest;Integrated Security=True;MultipleActiveResultSets=True;")
Dim cmd As New SqlClient.SqlCommand("select status from Table1", _conn)
Dim ds As New DataSet
_conn.Open()
While Not _done
Dim stat As String
stat = cmd.ExecuteScalar()
If Me.InvokeRequired() Then
Me.Invoke(Sub()
Me.Label1.Text = stat
End Sub)
Else
Me.Label1.Text = stat
End If
End While
_conn.Close()
End Sub
Я добавил простой способ перевернуть private boolean в классе формы в true, когда LongRunningProcess завершен.
Private Sub FinishProcess()
'_done is a private variable on the form class.
_done = True
End Sub
Наконец, в форме Load event я использую.NET-библиотеку задач, чтобы запустить проверку состояния и длительный процесс, гарантируя, что задача LongRunningProcess будет продолжена с завершением процесса.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Task.Factory.StartNew(AddressOf StatusChecker)
Task.Factory.StartNew(AddressOf LongRunningProcess).ContinueWith(AddressOf FinishProcess)
End Sub
Поэтому, когда все это выполняется, у нас есть фоновые потоки, выполняющие длительную задачу и проверяющие статус так часто, как нужно. Поскольку хранимая процедура обновляет таблицу 1 с информацией и выполняет эти инструкции в разных транзакциях, вы видите обновления по мере их возникновения.