在'Using'语句中选择@@ Identity

时间:2013-04-03 13:56:12

标签: c# sql-server-ce using

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

最近我一直在将我的代码转换为使用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();上会出现此错误。

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

3 个答案:

答案 0 :(得分:5)

来自@@IDENTITY documentation

  

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

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

答案 1 :(得分:0)

首先,@@Identity将从SQL Server的任何位置返回任何上次生成的ID 。很可能您需要使用SCOPE_IDENTITY()代替。

这显示了您的实际问题和设计问题 - 您需要将连接命令分开。 连接会嵌入交易,但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;
    }
}

使用连接时,可以创建如下的辅助方法:

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
}
...

答案 2 :(得分:0)

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

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

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

希望它可以帮到你