如何在 sqlInsertCmd.ExecuteNonQuery 之后执行 SqlDataReader
How do I execute a SqlDataReader after sqlInsertCmd.ExecuteNonQuery
我正在向我的 SQL 服务器数据库中插入一个数据行,然后我想查询数据以从插入的行中获取唯一标识符,但我的 SqlDataReader
返回一个空数据集。我在想可能是交易还没有提交或类似的事情,但我不确定。我没有收到错误。
这是我的代码:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
将以下行添加到插入记录的存储过程
SELECT SCOPE_IDENTITY()
这将 return 最后插入的身份值 table。
并使用 cmd.ExecuteScalar()
而不是 ExecuteNonQuery()
ExecuteScalar()
执行查询,return 是查询 return 结果集中第一行的第一列。忽略其他列或行。 [More info][1]
您没有得到想要的结果,因为可能 SqlConnection
没有明确打开(如果没有完整的代码,很难判断)。但是这个 link 向您展示了如何从 reader 读取 --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
但是我建议你不要这样做。原因是您要往返数据库服务器两次,而只有一次可以为您完成这项工作 IF 您使用的是存储过程。此外,由于您没有对查询进行参数化,因此您将自己暴露于 SQL 注入攻击。
存储过程:
CREATE PROCEDURE dbo.INS_clientnames
(
@FirstName varchar(100),
@LastName varchar(100),
@NewID int out
)
AS
BEGIN
Declare @Err int
set @NewID = NewID() -- Get the New ID and store it in the variable ( @NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (@NewID , @FirstName , @LastName)
SET @Err = @@ERROR
IF @Error <> 0 -- Check If there was an error
Begin
SET @NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
执行上述存储过程并获取 NewID 的 C# 代码:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("@LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("@NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["@FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["@LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from @NewId
int NewID = Convert.ToInt32(cmd.Parameters["@NewId"].Value);
}
}
我看到有两种方法可以做到这一点:
- 要么在客户端使用 C# 代码生成新的 GUID 并将其传递到查询中 - 那么您已经知道新的 ID 是什么,所以您无需进行第二次查询即可获得它:
- 您在服务器端创建您的 GUID,然后 return 使用查询中的
OUTPUT
子句将其发送给调用者
方法 #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(@ID, @First, @Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("@ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("@First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("@Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
方法 #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), @First, @Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("@First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("@Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}
我正在向我的 SQL 服务器数据库中插入一个数据行,然后我想查询数据以从插入的行中获取唯一标识符,但我的 SqlDataReader
返回一个空数据集。我在想可能是交易还没有提交或类似的事情,但我不确定。我没有收到错误。
这是我的代码:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
将以下行添加到插入记录的存储过程
SELECT SCOPE_IDENTITY()
这将 return 最后插入的身份值 table。
并使用 cmd.ExecuteScalar()
而不是 ExecuteNonQuery()
ExecuteScalar()
执行查询,return 是查询 return 结果集中第一行的第一列。忽略其他列或行。 [More info][1]
您没有得到想要的结果,因为可能 SqlConnection
没有明确打开(如果没有完整的代码,很难判断)。但是这个 link 向您展示了如何从 reader 读取 --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
但是我建议你不要这样做。原因是您要往返数据库服务器两次,而只有一次可以为您完成这项工作 IF 您使用的是存储过程。此外,由于您没有对查询进行参数化,因此您将自己暴露于 SQL 注入攻击。
存储过程:
CREATE PROCEDURE dbo.INS_clientnames
(
@FirstName varchar(100),
@LastName varchar(100),
@NewID int out
)
AS
BEGIN
Declare @Err int
set @NewID = NewID() -- Get the New ID and store it in the variable ( @NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (@NewID , @FirstName , @LastName)
SET @Err = @@ERROR
IF @Error <> 0 -- Check If there was an error
Begin
SET @NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
执行上述存储过程并获取 NewID 的 C# 代码:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("@LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("@NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["@FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["@LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from @NewId
int NewID = Convert.ToInt32(cmd.Parameters["@NewId"].Value);
}
}
我看到有两种方法可以做到这一点:
- 要么在客户端使用 C# 代码生成新的 GUID 并将其传递到查询中 - 那么您已经知道新的 ID 是什么,所以您无需进行第二次查询即可获得它:
- 您在服务器端创建您的 GUID,然后 return 使用查询中的
OUTPUT
子句将其发送给调用者
方法 #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(@ID, @First, @Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("@ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("@First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("@Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
方法 #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), @First, @Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("@First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("@Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}