使用SQL Server在C#中插入数据后返回id

7

我知道这个问题在这个网站上已经被问过很多次,但是我无法让我的代码工作。

我有一个Insert语句,我需要该语句的id在我的asp.net页面上。

我得到了返回值0

public int newid { get; set; }

public void CreateAlbum(string _titel, string _name, string _thumb, int _userid)
{
    objCMD = new SqlCommand(@"INSERT INTO tblFotoalbum 
                                  (fldAlbumHead, fldAlbumName, fldAlbumThumb, fldUserID_FK)
                              VALUES 
                                  (@titel, @name, @thumb, @userid);

                              SET @newid = SCOPE_IDENTITY()");

    objCMD.Parameters.AddWithValue("@titel", _titel);
    objCMD.Parameters.AddWithValue("@name", _name);
    objCMD.Parameters.AddWithValue("@thumb", _thumb);
    objCMD.Parameters.AddWithValue("@userid", _userid);
    objCMD.Parameters.AddWithValue("@newid", newid);

    objData.ModifyData(objCMD);       
}

你是否期望属性newid被设置为SCOPE_IDENTITY的值?这不是参数工作的方式。 - Steve
SELECT SCOPE_IDENTITY() - leppie
1
objData是什么?对该对象进行.ModifyData()操作会产生什么影响? - marc_s
Steve - 是的,那是我的想法,但我还不太精通 SQL :) - Henrik S
marc_s - objData 是我的 DataAccess 文件的一个实例,modifyData 是:public void ModifyData(SqlCommand CMD) { CMD.Connection = strCon; strCon.Open(); CMD.ExecuteNonQuery(); strCon.Close(); } - Henrik S
可能是重复的问题:如何获取最后插入的ID? - Tanner
7个回答

10

试一下:

public int CreateAlbum(string _titel, string _name, string _thumb, int _userid)
{
    // define return value - newly inserted ID
    int returnValue = -1;

    // define query to be executed
    string query = @"INSERT INTO tblFotoalbum (fldAlbumHead, fldAlbumName, fldAlbumThumb, fldUserID_FK)
                              VALUES (@titel, @name, @thumb, @userid);
                     SELECT SCOPE_IDENTITY();"

    // set up SqlCommand in a using block   
    using (objCMD = new SqlCommand(query, connection)) 
    {
        // add parameters using regular ".Add()" method 
        objCMD.Parameters.Add("@titel", SqlDbType.VarChar, 50).Value = _titel;
        objCMD.Parameters.Add("@name", SqlDbType.VarChar, 100).Value = _name;
        objCMD.Parameters.Add("@thumb", SqlDbType.VarChar, 100).Value = _thumb;
        objCMD.Parameters.Add("@userid", SqlDbType.VarChar, 25).Value = _userid;

        // open connection, execute query, close connection
        connection.Open();
        object returnObj = objCMD.ExecuteScalar();

        if(returnObj != null)
        {
           int.TryParse(returnObj.ToString(), out returnValue);
        }

        connection.Close();
    }

    // return newly inserted ID
    return returnValue;
}

不确定如何将其与您的 objData 类集成-也许您需要为该DAL类添加一个新方法来处理此事。

请查看Can we stop using AddWithValue() already?并停止使用.AddWithValue()-它可能会导致意外和令人惊讶的结果...


好的,我会尝试这样做,我该如何在我的ASP CodeBehind中访问返回值? - Henrik S
@HenrikS:新的ID值作为int类型从CreateAlbum方法返回... - marc_s

3

根据您正在使用的SQL语句,您需要将@newid配置为输出参数:

var newIdParam = objCMD.Parameters.Add("@newid", SqlDbType.Int32)
newIdParam.Direction = ParameterDirection.OutPut;

然后您使用ExecuteNonQuery命令执行该命令,之后您可以读取输出参数:

objCmd.ExecuteNonQuery();
int newId = Convert.ToInt32(newIdParam.Value);

编辑: 我猜测ModifyData方法设置了连接属性并调用了ExecuteNonQuery,所以你的代码应该是:

objData.ModifyData(objCMD);      
int newId = Convert.ToInt32(newIdParam.Value);

我遇到了一个错误:ExecuteNonQuery:连接属性尚未初始化 - Henrik S
显然,你需要设置objCmd的连接属性,并确保在执行之前它是打开状态:objCmd.Connection = YourConnection; - Jesús López
现在我只得到了值0。 - Henrik S
您确定 tblFotoalbum 表具有标识列吗? - Jesús López
我喜欢这个答案,因为它可以使用参数运行。 - nuander

1
如果您正在使用 CommandText,不要忘记在 CommandText 行的末尾添加 "SELECT SCOPE_IDENTITY()"

这更像是一条评论而不是答案。 - Yan Sklyarenko
我花了2个小时学习这个答案。也许由于我的糟糕英语,你误解了我的意思。 - Hakan Lekesiz
对于误解我深感抱歉。我的观点仅关于信息的形式,而非内容。当你回答问题时,你可能需要给出更详细的解释,以便提问者和其他人受益。在这种特定情况下,我希望能看到更多关于为什么不应该忘记添加 SELECT SCOPE_IDENTITY() 的细节。希望你明白我的意思。 - Yan Sklyarenko
是的,谢谢。这是我在这个平台上的第一条评论。 - Hakan Lekesiz

1

对于 SQL SERVER 2000,这可能是适用的。

  • 对于 2005+,请使用

    OUTPUT INSERTED.ID

例如:

INSERT INTO Roles(UserId)
OUTPUT INSERTED.ID
VALUES(@UserId)

这不仅仅适用于触发器吗? - leppie
也许你的意思是让OP使用OUTPUT子句? - Panagiotis Kanavos
你有没有从这里复制这段代码:https://dev59.com/s2435IYBdhLWcg3wxC9p#5228819。如果是的话,请链接到那个答案并说明你从哪里获取或修改了代码。即使如此,这仍然没有直接回答问题。 - Tanner
OUTPUT子句需要一个带有临时(内存中的)表的INTO!您应该完成您否则有效的示例。 - Thorsten Dittmar

0

0
你不需要一个输出变量来完成它。你可以使用 SELECT SCOPE_IDENTITY() 来获取数据库中最后插入的 id,并使用 DbCommandExecuteScalar() 方法。
public int newid { get; set; }

public void CreateAlbum(string _titel, string _name, string _thumb, int _userid)
{
    objCMD = new SqlCommand(@"INSERT INTO tblFotoalbum 
                           (fldAlbumHead, fldAlbumName, fldAlbumThumb, fldUserID_FK)
                           VALUES 
                           (@titel, @name, @thumb, @userid);

                           SELECT SCOPE_IDENTITY()");

    objCMD.Parameters.AddWithValue("@titel", _titel);
    objCMD.Parameters.AddWithValue("@name", _name);
    objCMD.Parameters.AddWithValue("@thumb", _thumb);
    objCMD.Parameters.AddWithValue("@userid", _userid);
    objCMD.Parameters.AddWithValue("@newid", newid);

    objData.ModifyData(objCMD);     


    newid = (int)objCMD.ExecuteScalar();
}

我不知道 objData 对象具体是做什么的,但请检查一下您执行命令的方式。


2
你是不是想用 SELECT 而不是 SET?无论如何,使用 OUTPUT inserted.ID 子句更可取。你只需使用一条 INSERT 语句,并且不必担心在同一批次中插入具有标识键的多个表。 - Panagiotis Kanavos
我们不知道ModifyData做什么,但这可能是在数据库中拥有重复记录的最佳方法。 - Steve
2
@FelipeOriani 这样做不会有好结果。ExecuteScalar运行的是全部内容,而不仅仅是SELECT SCOPE_IDENTITY。如果ModifyData插入一条记录,再次调用ExecuteScalar将插入另一份相同数据的拷贝。 - Steve
是的,Steve,原帖作者应该为我们提供ModifyData函数的作用。 - Felipe Oriani

0

首选方案(也是我所知道的唯一真正安全的方案)是使用OUTPUT子句,如下例:

DECLARE @newIdTable(newid INT);
INSERT INTO table(...) OUTPUT INSERTED.ID INTO @newIdTable VALUES (...);
SELECT TOP 1 newid FROM @newIdTable;

我建议您将此放入存储过程中,并使用ExecuteScalar调用它,这将返回最后一个select的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接