Select @@Identity inside 'Using' statement

本文关键字:statement Using @@Identity inside Select | 更新日期: 2023-09-27 18:07:24

我正在C#中编写Sql-Server-ce应用程序。

最近我一直在转换我的代码使用using语句,因为它们更干净。在我的代码中,我有一个非常简单的GetLastInsertedID函数-它返回最后插入的ID。工作版本如下:

    public static int GetLastInsertedID()
    {
        int key = 0;
        try
        {
            SqlCeCommand cmd = new SqlCeCommand("SELECT CONVERT(int, @@IDENTITY)", DbConnection.ceConnection);
            key = (int)cmd.ExecuteScalar();
        }
        catch (Exception ex)
        {
            MessageBox.Show("Could not get last inserted ID. " + ex.Message);
            key = 0;
        }
        return key;
    }

下面是不工作的代码,一旦我包装它在using语句:

    public static int GetLastInsertedID()
    {
        int key = 0;
        try
        {
            using (SqlCeConnection conn = new SqlCeConnection(DbConnection.compact))
            {
                conn.Open();
                using (SqlCeCommand cmd = new SqlCeCommand("SELECT CONVERT(int, @@IDENTITY)", conn))
                    key = (int)cmd.ExecuteScalar();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Could not get last inserted ID. " + ex.Message);
            key = 0;
        }
        return key;
    }

我得到的错误是specified cast is not valid。虽然这个错误通常是不言自明的,但我不明白为什么我会在第二个代码块中得到它,而不是在第一个代码块中。这个错误发生在key = (int)cmd.ExecuteScalar();行。

我对第二块代码做错了什么?

Select @@Identity inside 'Using' statement

来自@@IDENTITY文档:

@@IDENTITY和SCOPE_IDENTITY将返回当前会话中任何表的最后一个标识值。

我认为你的修改现在为每个using语句启动一个新的会话。因此@@IDENTITY为空

首先,@@Identity将返回任何最后生成的ID从SQL Server的任何地方。最有可能的是,您需要使用SCOPE_IDENTITY()

这显示了您的实际问题和设计问题-您需要保持连接命令分开。Connection嵌入事务,尽管SCOPE_IDENTITY()将工作直到连接关闭;命令可以创建、使用和处置。

所以你需要接受connection的方法,并使用它来获得身份-就像这样(没有检查它,但认为想法应该清楚):

public static int GetLastInsertedID(DbConnection connection)
{
    try
    {
        string query = "SELECT CONVERT(int, SCOPE_IDENTITY())";
        using (SqlCeCommand cmd = new SqlCeCommand(query, conn)) {
            return (int)cmd.ExecuteScalar();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Could not get last inserted ID. " + ex.Message);
        return 0;
    }
}

对于连接,您可以创建这样的helper方法:

public static SqlCeConnection OpenDefaultConnection()
{
    SqlCeConnection conn = new SqlCeConnection(DbConnection.compact);
    conn.Open();
    return conn;
}

并像这样使用:

...
using (SqlCeConnection conn = OpenDefaultConnection()) {
    //... do smth
    int id = GetLastInsertedID(conn);
    //... do smth
}
...

在我看来,它不起作用的原因与using statement无关。

如果使用静态类来完成连接数据库的操作,如DBHelper。这个问题是由于你在执行select @@identity之前关闭了数据库连接,而在执行select @@identity的时候又重新打开了数据库连接。这个执行序列将导致select @@identity的返回结果为NULL。也就是说,您不能两次使用DBHelper.xxx()来获取自动ID,因为每次调用DBHelper.xxx()时,都会执行打开数据库和关闭数据库的过程。

我有一个解决方案,但它可能不是最好的。您可以使用select count(*) from xxx而不是select @@identity来获得相同的结果。

希望对你有帮助