【问题标题】:SCOPE_IDENTITY in C# - rangeC# 中的 SCOPE_IDENTITY - 范围
【发布时间】:2010-10-12 09:15:51
【问题描述】:

我查看了SCOPE_IDENTITY() 的文档,上面写着“作用域是一个模块:存储过程、触发器、函数或批处理。”当我在 SSMSE 中运行查询时,这很简单,但在 C# 中,我使用 SqlCommand 来执行我的语句。

问题是:那里的范围是什么?在一个连接下执行后续命令是否等同于批处理?或者也许每个命令都在不同的范围内,我需要一个事务才能工作?

【问题讨论】:

    标签: c# sql-server


    【解决方案1】:

    我建议将 C# 命令和 T-SQL“批处理”视为彼此完全独立的。

    仅将 SQLCommand 视为您的执行包装器,其中构成批处理的实际定义由 T-SQL 语言定义和控制。

    您的会话范围在 Connection 对象级别维护。

    您可能会发现以下 MSDN 论坛帖子很有趣。注意第一个示例如何执行两个单独的 SQL 命令,但第二个调用的 SCOPE_IDENITY() 可以看到前一个调用的结果。这是因为当前范围在连接级别是可见的。

    SQLCommand With Parameters and Scope_Indentity

    为了解释的完整性,使用参数不起作用的原因,如后面链接示例中所示,是因为 sp_executesql 在它自己的范围内执行,因此看不到连接的范围。

    [编辑]

    更多好奇读者的进一步阅读,请在下面找到 VB.NET 代码,该代码提供了在单个连接上执行两个单独命令的示例,第二个命令成功发出 SCOPE_IDENTITY() 函数。

    可以从 SSIS 包任务的 SCRIPT 组件中执行源代码。您还需要为您的环境编辑连接详细信息并创建引用的表对象。

    创建表脚本:

    create table TestTable
    (
        ID int identity(1,1) primary key not null,
        SomeNumericData int not null
    );
    

    VB.NET 源码列表:

    Imports System
    Imports System.Data
    Imports System.Math
    Imports Microsoft.SqlServer.Dts.Runtime
    Imports System.Data.SqlClient.SqlConnection
    Imports Windows.Forms.MessageBox
    
    Public Class ScriptMain
    
    
    
        Public Sub Main()
            '
            ' Add your code here
    
            Dim oCnn As New Data.SqlClient.SqlConnection
            Dim sSQL As String
            Dim sSQL2 As String
            Dim resultOne As Integer
            Dim resultTwo As Integer
            Dim messageBox As Windows.Forms.MessageBox
    
            resultOne = 0
            resultTwo = 0
    
            oCnn.ConnectionString = "Server=ServerName;Database=DatabaseName;Trusted_Connection=true"
            sSQL = "INSERT INTO TestTable(SomeNumericData) VALUES(666) "
            sSQL2 = "SELECT SCOPE_IDENTITY()"
            Dim oCmd As SqlClient.SqlCommand = New SqlClient.SqlCommand(sSQL, oCnn)
            Dim oCmd2 As SqlClient.SqlCommand = New SqlClient.SqlCommand(sSQL2, oCnn)
    
            oCmd.CommandType = CommandType.Text
            oCmd.Connection = oCnn
            oCnn.Open()
    
            resultOne = oCmd.ExecuteNonQuery()
            resultTwo = Convert.ToInt32(oCmd2.ExecuteScalar())
    
            oCnn.Close()
    
            messageBox.Show("result1:" + resultOne.ToString + Environment.NewLine + "result2: " + resultTwo.ToString)
    
            Dts.TaskResult = Dts.Results.Success
        End Sub
    End Class
    

    【讨论】:

    • “这是因为范围在连接级别保持/可见。”我不同意你的观点。范围取决于你在查询中指定 scope_identity() 的位置,在链接的示例 1 中,在 2 个查询中执行了不同的命令。因为两者都在不同的范围内,所以它返回 null ......所以范围仅限于每个命令......而不是连接......
    • @Ramesh Vel:请找到对原始帖子的编辑,以包含验证连接中两个单独命令的会话范围可见性的源代码。
    • 我已经完成了几乎相同类型的测试,但是在 C# 中并在单独的命令中执行 SCOPE_IDENTITY() 效果很好,即使我在调用 insert 和select scope_identity()(控制台应用程序,命令之间的ReadLine())
    • @Ramesh Vel:我还建议您不要发布笼统的声明,除非您能够验证它们。这是不负责任的,因为有些读者会把你的 cmets 当作福音。范围不是由指定 SCOPE_IDENTITY() 函数的位置决定的,它在 T-SQL 代码中的定位对活动会话范围没有影响或控制。
    【解决方案2】:

    我相信范围只适用于单个命令,而不适用于整个连接。

    strSQL = "INSERT INTO tablename (name) VALUES (@name);SELECT SCOPE_IDENTITY()"
    SQLCommand.CommandText = strSQL
    Id = SQLCommand.ExecuteScalar()
    

    在上面的代码中,strSQL是一个完整的作用域,它总是返回关联插入语句的@@identity值。

    因此后续命令将有自己的范围。

    【讨论】:

    • 我倾向于不同意你的观点。
    • @Ramesh Vel:以下示例代码似乎另有建议:social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/…
    • @John,你检查了完整的查询吗, SELECT SCOPE_IDENTITY() 是内联的,所以这将在一个范围内执行。这种方法确保 scope_identity 在每个命令的范围内运行。 ..
    • @Ramesh Vel:您发布的源代码是正确的,但不是我要争论的。我对您的观点提出异议,即在同一连接上执行的后续命令将具有自己单独的范围。情况不一定如此。
    • @kubal5003,是的,如果您使用的是过程,那么范围将在 sp。如果您在单个连接中执行多个命令,并且 SELECT SCOPE_IDENTITY() 作为单独的命令,则范围将丢失(意味着结果不会是预期的).. 如果您想获得您的范围,请内联使用它特定命令...
    猜你喜欢
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 2021-11-14
    • 2011-01-06
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    相关资源
    最近更新 更多