14

我需要一个在数据库上执行 INSERT 语句并返回 Auto_Increment 主键的函数。我有以下 C# 代码,但是,虽然 INSERT 语句工作正常(我可以看到数据库中的记录,PK 生成正确并且行 == 1),但 id 值始终为 0。关于可能发生的任何想法错误的?

    public int ExecuteInsertStatement(string statement)
    {
        InitializeAndOpenConnection();
        int id = -1;


        IDbCommand cmdInsert = connection.CreateCommand();
        cmdInsert.CommandText = statement;
        int rows = cmdInsert.ExecuteNonQuery();

        if (rows == 1)
        {
            IDbCommand cmdId = connection.CreateCommand();
            cmdId.CommandText = "SELECT @@Identity;";
            id = (int)cmdId.ExecuteScalar();
        }

        return id;
    }
    private void InitializeAndOpenConnection()
    {
        if (connection == null)
            connection = OleDbProviderFactory.Instance.CreateConnection(connectString);

        if(connection.State != ConnectionState.Open)                 
            connection.Open();
    }

为了回应答案,我尝试了:

public int ExecuteInsertStatement(string statement, string tableName)
    {
        InitializeAndOpenConnection();
        int id = -1;
        IDbCommand cmdInsert = connection.CreateCommand();
        cmdInsert.CommandText = statement + ";SELECT OID FROM " + tableName + " WHERE OID = SCOPE_IDENTITY();";
        id = (int)cmdInsert.ExecuteScalar();

        return id;
    }

但我现在收到错误“SQL 语句结束后找到的字符”

我正在使用带有 OleDb 连接的 MS Access 数据库,Provider=Microsoft.Jet.OLEDB.4.0

4

13 回答 13

15

1) 将 INSERT 和 SELECT 语句(使用“;”连接)组合成 1 个 db 命令

2) 使用 SCOPE_IDENTITY() 而不是 @@IDENTITY

插入 blabla ... ; 从表中选择 OID WHERE OID = SCOPE_IDENTITY()

- 更新:

事实证明,这个问题与 MS ACCESS 有关,我发现这篇文章表明只需重用第一个命令并将其 CommandText 设置为“SELECT @@IDENTITY”就足够了。

于 2008-10-09T09:42:35.170 回答
7

Microsoft.Jet.OLEDB.4.0 提供程序支持 Jet v3 和 Jet v4 数据库引擎,但是 Jet v3 不支持 SELECT @@IDENTITY。

MSAccess 97 是 Jet v3,不支持 SELECT @@IDENTITY;它支持 MSAccess 2000 及更高版本。

于 2008-10-09T12:13:57.687 回答
4

您需要在打开初始连接的同时返回身份。从插入或输出变量返回结果集。

您还应该始终使用 SCOPE_IDENTITY() 而不是 @@identity。参考这里

你应该添加

SELECT SCOPE_IDENTITY() 

插入后。

于 2008-10-09T09:42:50.567 回答
4

您使用的是 Jet(不是 SQL Server),而 Jet 每个命令只能处理一个 SQL 语句,因此您需要SELECT @@IDENTITY在单独的命令中执行,显然要确保它使用与INSERT.

于 2008-10-09T10:22:45.523 回答
1

我认为您需要在第一个创建命令中使用 Select @@identity - 尝试通过 ";SELECT @@Identity" 和 .ExecuteScalar 插入语句附加它

于 2008-10-09T09:40:54.797 回答
0

如果您想检索您正在插入的事务的自动运行数的值以及您的环境如下 1. 数据库是 MsAccess。2. 驱动程序是 Jet4,连接字符串如下“Provider=Microsoft.Jet.OLEDB.4.0;Password={0};Data Source={1};Persist Security Info=True” 3. 使用 Oledb

您可以将我的示例应用于您的代码

OleDbConnection connection =  String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Password={0};Data Source={1};Persist Security Info=True",dbinfo.Password,dbinfo.MsAccessDBFile);
connection.Open();
OleDbTransaction transaction = null;
try{
    connection.BeginTransaction();
    String commandInsert = "INSERT INTO TB_SAMPLE ([NAME]) VALUES ('MR. DUKE')";
    OleDbCommand cmd = new OleDbCommand(commandInsert , connection, transaction);
    cmd.ExecuteNonQuery();
    String commandIndentity = "SELECT @@IDENTITY";
    cmd = new OleDbCommandcommandIndentity, connection, transaction);
    Console.WriteLine("New Running No = {0}", (int)cmd.ExecuteScalar());
    connection.Commit();
}catch(Exception ex){
    connection.Rollback();
}finally{
    connection.Close();
}   
于 2009-05-22T23:19:27.037 回答
0

您的表上是否有任何可能插入到其他表中的触发器?通常,我们建议不要使用@@Identity 来支持IDENT_CURRENT,这样您就可以保证返回的身份是针对您刚刚插入的表的。

于 2008-10-09T09:41:39.803 回答
0

我认为 @@identity 仅在命令范围内有效 - 在您执行“语句”时。

修改您的“语句”,使存储过程本身在 INSERT 语句之后立即返回 @@IDENTITY 值,并将其读取为存储过程执行的返回码。

于 2008-10-09T09:42:24.937 回答
0

检查您的数据库设置。不久前我遇到了类似的问题,发现启用了 SQL Server 连接设置“无计数”。

在 SQL Server Management Studio 中,您可以通过右键单击对象资源管理器中的服务器,选择“属性”,然后导航到“连接”页面来找到它。查看“默认连接选项”的设置

于 2008-10-09T10:00:25.010 回答
0

大多数回答者不是忘记了提问者没有使用 SQL Server 吗?

显然,MS Access 2000 及更高版本不支持 @@IDENTITY另一种方法是“使用 RowUpdated 事件,您可以确定是否发生了 INSERT,检索最新的 @@IDENTITY 值,并将其放在 DataSet 中本地表的标识列中。”

是的,这是用于 Access DB 中的嵌入式 VBA。这仍然可以通过 Access 对象库在 Access 之外调用。

编辑:好的,它受支持,对于昏昏沉沉的清晨回答感到抱歉。但是这个答案的其余部分可能会有所帮助。

于 2008-10-09T10:51:00.757 回答
0

简短的回答:
1. 创建两个命令,每个命令都接受一个查询。
2.第一个sql查询是INSERT记录。
3.第二个sql查询是“SELECT @@Identity;” 它返回自动编号。
4. 使用 cmd.ExecuteScalar() 返回第一行的第一列。
5、返回的结果输出为当前插入查询中生成的AutoNumber值。

它是从此链接中引用的。示例代码如下。请注意“相同连接与新连接”的区别。SAME Con​​nection 提供所需的输出。

 class Program
{
    static string path = @"<your path>";
    static string db = @"Test.mdb";
    static void Main(string[] args)
    {
        string cs = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\{1}", path, db);
        // Using the same connection for the insert and the SELECT @@IDENTITY
        using (OleDbConnection con = new OleDbConnection(cs))
        {
            con.Open();
            OleDbCommand cmd = con.CreateCommand();
            for (int i = 0; i < 3; i++)
            {
                cmd.CommandText = "INSERT INTO TestTable(OurTxt) VALUES ('" + i.ToString() + "')";
                cmd.ExecuteNonQuery();

                cmd.CommandText = "SELECT @@IDENTITY";
                Console.WriteLine("AutoNumber: {0}", (int)cmd.ExecuteScalar());
            }
            con.Close();
        }
        // Using a new connection and then SELECT @@IDENTITY
        using (OleDbConnection con = new OleDbConnection(cs))
        {
            con.Open();
            OleDbCommand cmd = con.CreateCommand();
            cmd.CommandText = "SELECT @@IDENTITY";
            Console.WriteLine("\nNew connection, AutoNumber: {0}", (int)cmd.ExecuteScalar());
            con.Close();
        }
    }
}

这应该产生不言自明的输出:

AutoNumber: 1 <br>
AutoNumber: 2 <br>
AutoNumber: 3 <br>

New connection, AutoNumber: 0
于 2015-06-02T18:10:19.440 回答
-1

当您使用 Access 时,请查看 aspfaq 中的这篇文章,向下滚动到页面的大约一半。代码在经典 ASP 中,但希望这些原则仍然有效。


我相信 SELECT @@Identity 最终会被视为一个单独的执行上下文。应该工作的代码是:

public int ExecuteInsertStatement(string statement)
{
    InitializeAndOpenConnection();

    IDbCommand cmdInsert = connection.CreateCommand();
    cmdInsert.CommandText = statement + "; SELECT @@Identity";
    object result = cmdInsert.ExecuteScalar();

    if (object == DBNull.Value)
    {
       return -1;
    }
    else
    {
       return Convert.ToInt32(result);
    }
}

不过,您可能希望/需要整理将“SELECT @@Identity”添加到代码末尾的连接。

于 2008-10-09T09:42:42.360 回答
-2
CREATE procedure dbo.sp_whlogin
(
 @id nvarchar(20),
 @ps nvarchar(20),
 @curdate datetime,
 @expdate datetime
)

AS
BEGIN
 DECLARE @role nvarchar(20)
 DECLARE @menu varchar(255)
 DECLARE @loginid int

 SELECT     @role = RoleID
 FROM         dbo.TblUsers
 WHERE    UserID = @id AND UserPass = @ps

 if @role is not null 
 BEGIN
  INSERT INTO TblLoginLog (UserID, LoginAt, ExpireAt, IsLogin) VALUES (@id, @curdate, @expdate, 1);
  SELECT @loginid = @@IDENTITY;
  SELECT @loginid as loginid, RoleName as role, RoleMenu as menu FROM TblUserRoles WHERE RoleName = @role
 END
 else
 BEGIN
  SELECT '' as role, '' as menu
 END
END
GO
于 2010-01-10T08:22:25.980 回答