Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 将结果集从SQL Server返回到VB.NET应用程序_Sql Server_Vb.net_Resultset_Cursors - Fatal编程技术网

Sql server 将结果集从SQL Server返回到VB.NET应用程序

Sql server 将结果集从SQL Server返回到VB.NET应用程序,sql-server,vb.net,resultset,cursors,Sql Server,Vb.net,Resultset,Cursors,我需要返回一个由SQL Server存储过程的CATCH子句中的数据库错误组成的结果集,但我一直在使用它。我是否需要使用游标来返回结果集?如果需要,那么.NET应用程序中的输出参数的类型声明是什么?我尝试了对象和变量,但没有成功 我还尝试了使用SELECT语句返回的简单方法,它适用于一个存储过程,但不适用于另一个存储过程,如我的CATCH子句中所述: while (@I <= @count) begin BEGIN TRY -- del

我需要返回一个由SQL Server存储过程的
CATCH
子句中的数据库错误组成的结果集,但我一直在使用它。我是否需要使用游标来返回结果集?如果需要,那么.NET应用程序中的
输出
参数的类型声明是什么?我尝试了
对象
变量
,但没有成功

我还尝试了使用
SELECT
语句返回的简单方法,它适用于一个存储过程,但不适用于另一个存储过程,如我的
CATCH
子句中所述:

 while (@I <= @count)
 begin      
    BEGIN TRY       
        -- delete all previous rows inserted in @customerRow for previous counts @I     
        delete from @customerRow

        -- this is inserting the current row that we want to save in database
        insert into @customerRow 
           SELECT  
               [id],[firstname], [lastname], [street], [city],
               [phone],[mobile],[fax], [email], [companyName],
               [licence],[brn], [vat], [companyStreet], [companyCity], [status]
           FROM 
               (SELECT  
                   ROW_NUMBER() OVER (ORDER BY id ASC) AS rownumber,
                   [id], [firstname], [lastname], [street], [city],
                   [phone], [mobile], [fax], [email], [companyName],
                   [licence], [brn], [vat], [companyStreet], [companyCity], [status]
                FROM    
                   @registerDetails) AS foo
          WHERE 
             rownumber = @I                                             

       -- this stored procedure handles the saving of the current customer row just defined above
        -- if there is any error from that sproc, it will jump to CATCH block 
        --save the error message in the temp table and continue 
        --with the next customer row in the while loop.
        exec dbo.sp_SaveCustomer @customerRow
    END TRY
    BEGIN CATCH
        IF @@TranCount = 0
        -- Transaction started in procedure.
        -- Roll back complete transaction.
        ROLLBACK TRANSACTION;
        if XACT_STATE()= -1 rollback transaction

        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;


        SELECT @ErrorMessage = ERROR_MESSAGE() + ' ' + (select firstname from @registerDetails where id=@I)
        SELECT @ErrorSeverity = ERROR_SEVERITY();
        SELECT @ErrorState = ERROR_STATE() 

        INSERT INTO #registrationResults (error,id)
        SELECT @ErrorMessage, @I 

    END CATCH       

    set @I = @I +1              
end 
COMMIT TRANSACTION registerTran

select * from #registrationResults
其中,
registrationErrors
clientDetailsDT
是强类型数据表

这一条没有:

    begin catch
    IF @@TranCount > 0 or XACT_STATE()= -1 ROLLBACK TRANSACTION;
    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;
    DECLARE @ErrorLine INT;


    SELECT @ErrorMessage = ERROR_MESSAGE();
    SELECT @ErrorSeverity = ERROR_SEVERITY();
    SELECT @ErrorState = ERROR_STATE();
    SELECT @ErrorLine = ERROR_Line();

    ****ERROR -- THIS SELECT WAS MESSING ALL UP as it was this select that was being        returned to the .NET and not the select of the desired #temp table after, hence returning 0    resultset as this select was EMPTY. !!  
    select status_indicator from InsertInvoiceTriggerData where session_GUID =   guid**
    delete from InsertInvoiceTriggerData where session_GUID = @guid**

    INSERT INTO #registrationResults (error,id)
    SELECT @ErrorMessage, NULL

    select * from #registrationResults

end catch

有没有关于如何返回结果集的建议?

我没有看到您的数据库代码,但根据我的经验,
catch
捕获的第一个错误意味着整个事务必须回滚。除此之外,它还意味着在任何给定的情况下,我都不会返回超过1个错误

因此,我在存储过程中使用了2个标量输出参数,即:

@Error int = null output,
@Message nvarchar(2048) = null output
我可以像检索任何其他输出变量一样检索它们

UPD:即使您添加了一些代码,我仍然无法准确理解您的问题所在。但是,我发现您的代码有几个问题,所以我将指出它们,其中一个可能会解决问题。我只评论第一个片段,因为最后一个片段太不完整了

  • 您应该在循环之前的某个位置启动最外层的事务。否则,代码将失败
  • 如果我猜对了,您在
    dbo.sp\u SaveCustomer
    存储过程中实现了所有保存点逻辑。如果没有,整个讨论就毫无意义,因为在您显示的代码中没有
    save-tran
    rollback@savepoint
    语句
  • 第一个
    catch
    语句-
    IF@@tracount=0回滚事务
    都是错误的。如果条件成功,将导致尝试回滚不存在的事务时出错。如果您依赖保存点,则不应出现在此处
  • 它后面的下一个应该导致无条件中断:
    
    如果XACT_STATE()=-1开始
    回滚事务;
    打破
    结束
  • 捕获代码的其余部分可以替换为:
    
    插入@registrationResults(错误,id)
    选择error_message()+“”+firstname,id
    来自@registerDetails,其中id=@I
  • 此外,千万不要为此使用临时表,因为回滚也会影响临时表。为此,请始终使用表变量,它们是非事务性的(与任何其他变量一样)
  • commit
    应该是有条件的,因为此时您可能没有要提交的事务:
    
    如果@trancount>0,则提交传输
  • commit
    语句中指定保存点名称没有意义,它只会导致混淆(尽管不被视为错误)。此外,此模块中不应该有任何保存点(除非您在循环之前定义了它)
我怀疑这只是冰山一角,因为我不知道
dbo.SaveCustomer
存储过程中实际发生了什么

UPD2:以下是我用来从存储过程接收记录集的VB.NET代码示例:

Private Function SearchObjectsBase( _
    SearchMode As penum_SEARCH_MODE, SearchCriteria As String
) As DataSet

Dim Cmd As DbCommand, Pr As DbParameter, dda As DbDataAdapter

' Initialise returning dataset object
SearchObjectsBase = New DataSet()

Cmd = MyBase.CreateCommand(String.Format("dbo.{0}", SearchMode))

With Cmd

    ' Parameter definitions
    Pr = .CreateParameter()
    With Pr
        .ParameterName = "@SearchCriteria"
        .DbType = DbType.Xml
        .Value = SearchCriteria
    End With
    .Parameters.Add(Pr)

    ' Create data adapter to use its Fill() method
    dda = DbProviderFactories.GetFactory(.Connection).CreateDataAdapter()
    ' Assign the prepared DbCommand as a select method for the adapter
    dda.SelectCommand = Cmd

    ' A single resultset is expected here
    dda.Fill(SearchObjectsBase)

End With

' Set error vars and get rid of it
Call MyBase.SetErrorOutput(Cmd)

' Check for errors and, if any, discard the dataset
If MyBase.ErrorNumber <> 0 Then SearchObjectsBase.Clear()

End Function

这里,SearchPatients()是SearchObjectsBase()之上的包装器。

标量参数可以很好地处理您提到的单个输出,但在我的例子中,我有一个事务在while循环中进行,每次事务没有成功,它都会回滚到保存点,并如上所述将错误消息保存在临时表中。循环完成后,返回结果集fine。但是如果您想从CATCH块返回temp表中提到的参数,您将如何实现它?那么,您可以将错误结果集转换为XML,并通过XML输出参数返回它。因为,即使到2014年,表变量参数仍然是只读的。请再次查看原始帖子,我已经包含了数据库代码。另外,根据MSDN文档,这在存储过程之间起作用,但是我们如何从.NET读取游标呢?恐怕我不能理解你的问题。你有正确的代码和错误的代码;为什么要用错的呢?它将为每个错误生成一个单独的记录集,每个错误中只有一行。为什么不能使用正确的游标?而且,就为了记录,返回游标的参数的数据类型被称为
cursor
。但我一点也不知道如何在客户端处理它,假设这是可能的。
Private Function SearchObjectsBase( _
    SearchMode As penum_SEARCH_MODE, SearchCriteria As String
) As DataSet

Dim Cmd As DbCommand, Pr As DbParameter, dda As DbDataAdapter

' Initialise returning dataset object
SearchObjectsBase = New DataSet()

Cmd = MyBase.CreateCommand(String.Format("dbo.{0}", SearchMode))

With Cmd

    ' Parameter definitions
    Pr = .CreateParameter()
    With Pr
        .ParameterName = "@SearchCriteria"
        .DbType = DbType.Xml
        .Value = SearchCriteria
    End With
    .Parameters.Add(Pr)

    ' Create data adapter to use its Fill() method
    dda = DbProviderFactories.GetFactory(.Connection).CreateDataAdapter()
    ' Assign the prepared DbCommand as a select method for the adapter
    dda.SelectCommand = Cmd

    ' A single resultset is expected here
    dda.Fill(SearchObjectsBase)

End With

' Set error vars and get rid of it
Call MyBase.SetErrorOutput(Cmd)

' Check for errors and, if any, discard the dataset
If MyBase.ErrorNumber <> 0 Then SearchObjectsBase.Clear()

End Function
Dim XDoc As New XElement("Criteria"), DS As DataSet = Nothing, DT As DataTable
...
DS = .SearchPatients(XDoc.ToString(SaveOptions.None))
' Assign datasource to a grid
Me.dgr_Search.DataSource = DS.Tables.Item(0)