2016-07-29 10 views
0

Я вставляю строку данных в свою базу данных SQL Server, а затем я хочу запросить данные, чтобы получить уникальный идентификатор из вставленной строки, но мой возвращает пустой набор данных. Я думаю, что, возможно, сделка не была совершена или что-то в этом роде, но я не уверен. Я не получаю сообщение об ошибке.Как выполнить SqlDataReader после sqlInsertCmd.ExecuteNonQuery

Вот мой код:

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."); 
} 
+1

[SQL Injection предупреждение] (http://msdn.microsoft.com/en-us/library/ms161953 % 28v = SQL. 105% 29.aspx) - вы должны ** не ** объединить свои SQL-запросы - используйте ** параметризованные запросы **, чтобы избежать SQL-инъекции –

ответ

0

Вы не получаете желаемого результата, потому что, возможно, SqlConnection не открывается явно (просто трудно понять, не имея полного кода). Но эта ссылка показывает вам, как читать с читателя ->https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx

Но я предлагаю вам, пожалуйста, не делать этого таким образом. Причина в том, что вы делаете две круглые поездки на сервер БД, если только один выполнил бы эту работу для вас IF вы использовали хранимые процедуры. Также вы подвергаете себя атакам SQL Injection, поскольку вы не параметризуете свои запросы.

Хранимая процедура:

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 

C# код для выполнения выше хранимой процедуры и получить NewID:

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); 
    } 
} 
+0

Извините мое невежество, я довольно новичок в C#. Почему все рекомендуют параметризованные запросы? Почему конкатенация так плоха? – Cass

+0

@ Касс идти через эту статью: http://www.w3schools.com/sql/sql_injection.asp также есть много материала о SO об этом ... просто Google SQL инъекции. – objectNotFound

+0

#objectNotFound - Спасибо за информацию. Я думаю, что я начинаю это делать. Я преобразовал свой код в ваш пример, спасибо за всю помощь. Такой форум действительно полезен. – Cass

0

Добавьте следующую строку в хранимую процедуру, которая вставляет запись

SELECT SCOPE_IDENTITY() 

Это возвращает последнее значение идентичности, вставленное в этой таблице.

И использовать cmd.ExecuteScalar() вместо ExecuteNonQuery()

ExecuteScalar() выполняет запрос и возвращает первый столбец первой строки в наборе результатов, возвращаемого запросом. Дополнительные столбцы или строки игнорируются. [More info][1]

+0

#Antonio Avndaño Duran - Есть ли способ сделать это динамически? Я не использую хранимую процедуру. – Cass

+0

, конечно, отправьте запрос в текстовой форме, просто добавьте SELECT SCOPE_IDENTITY() после вставки sentece. EJ.«Вставить в значения таблицы (значение1, значение2, значение3); SCOPE_IDENTITY();» –

+0

, используя ваш пример 'strQuery = "INSERT INTO clientnames VALUES (NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + "); SCOPE_IDENTITY();'" ; –

0

я вижу два подхода, чтобы сделать это:

  1. либо вы сгенерируйте новый GUID на стороне клиента в коде C# и передайте его в запрос - тогда вы уже знаете, каким будет новый идентификатор, поэтому вам не нужно делать второй запрос для его получения:
  2. вы создаете свой GUID на стороне сервера и возвращаете его вызывающему, используя предложение 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(); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^