2013-01-09 8 views
20

Próba sprawdzenia, czy najlepiej jest użyć ExecuteScalar lub ExecuteNonQuery, jeśli chcę zwrócić kolumnę tożsamości nowo wstawionego wiersza. Czytałem this question i zrozumieć różnice istnieją, ale patrząc na niektóre kodu pisałem kilka tygodni temu (podczas gdy mocno pożyczania od tej strony) Okazało się, że w moich wstawek używałem ExecuteScalar, tak:ExecuteScalar vs ExecuteNonQuery podczas zwracania wartości tożsamości

public static int SaveTest(Test newTest) 
{ 
    var conn = DbConnect.Connection(); 
    const string sqlString = "INSERT INTO dbo.Tests (Tester , Premise) " + 
          "    VALUES (@tester , @premise) " + 
          "SET @newId = SCOPE_IDENTITY(); "; 
    using (conn) 
    { 
     using (var cmd = new SqlCommand(sqlString, conn)) 
     { 
      cmd.Parameters.AddWithValue("@tester", newTest.tester); 
      cmd.Parameters.AddWithValue("@premise", newTest.premise); 
      cmd.Parameters.Add("@newId", SqlDbType.Int).Direction = ParameterDirection.Output; 

      cmd.CommandType = CommandType.Text; 
      conn.Open(); 
      cmd.ExecuteScalar(); 

      return (int) cmd.Parameters["@newId"].Value; 
     } 
    } 
} 

działa to dobrze, za to, co muszę, więc zastanawiam

  1. Czy powinienem używać ExecuteNonQuery tutaj, bo to jest bardziej „właściwego” do wykonywania wkładek?
  2. Czy pobieranie wartości tożsamości było takie samo w obu kierunkach, ponieważ używam parametru wyjściowego?
  3. Czy są jakieś trafienia związane z wydajnością powiązane z takim czy innym sposobem?
  4. Czy ogólnie można to zrobić ogólnie?

Używam Visual Studio 2010, .NET 4.0 i SQL Server 2008r2, w przypadku, które robi różnicę.

+4

(1) dlaczego "ExecuteNonQuery" jest bardziej właściwy "? (2) czy rozważałeś zastosowanie procedur przechowywanych? Jeśli nie, dlaczego nie? Z pewnością pomoże to w wyczyszczeniu wszystkich ad hoc SQL, które wstawiasz do swojej aplikacji - które, gdy będziesz musiał je zmienić, oznaczają, że musisz ponownie skompilować i ponownie wdrożyć aplikację. –

+2

Hmmm ... ExecuteNonQuery służy zwykle do wykonywania SQL, który nie oczekuje zwrotu wyniku. ExecuteScalar zwraca wartość, więc nie trzeba przechodzić przez parametry. Możesz zmienić ostatnią część twojego SQL na 'SELECT SCOPE_IDENTITY(); następnie użyj' return (int) cmd.ExecuteScalar(); ' – Sam

+2

Używam' ExecuteScalar', ponieważ używam 'SELECT SCOPE_IDENTITY' bez parametru wyjściowego, stąd pobrać pojedynczą wartość, która jest celem 'ExecuteScalar'. http://stackoverflow.com/a/9319609/284240 –

Odpowiedz

25

Zgodnie z sugestią Aarona procedura składowana spowodowałaby, że byłaby szybsza, ponieważ zapisuje serwer Sql podczas kompilowania pakietu SQL. Jednak nadal możesz wybrać jedną z następujących metod: ExecuteScalar lub ExecuteNonQuery. IMHO, różnica w wydajności między nimi jest tak mała, że ​​każda z tych metod jest tak samo "właściwa".

Powiedziawszy to, nie widzę sensu używania ExecuteScalar, jeśli przechwytujesz wartość tożsamości z parametru wyjściowego. W takim przypadku wartość zwrócona przez ExecuteScalar staje się bezużyteczna.

Podejście, które lubię, ponieważ wymaga mniej kodu, wykorzystuje ExecuteScalar bez parametrów wyjściowych:

public static int SaveTest(Test newTest) 
{ 
    var conn = DbConnect.Connection(); 
    const string sqlString = "INSERT INTO dbo.Tests (Tester , Premise) " + 
          "    VALUES (@tester , @premise) " + 
          "SELECT SCOPE_IDENTITY()"; 
    using (conn) 
    { 
     using (var cmd = new SqlCommand(sqlString, conn)) 
     { 
      cmd.Parameters.AddWithValue("@tester", newTest.tester); 
      cmd.Parameters.AddWithValue("@premise", newTest.premise); 

      cmd.CommandType = CommandType.Text; 
      conn.Open(); 
      return (int) (decimal) cmd.ExecuteScalar(); 

     } 
    } 
} 

okazji programowania!

EDIT: Zauważ, że musimy oddać dwukrotnie: od obiektu do decimal, a następnie do int (dzięki techturtle dla zauważając tego).

+0

Wpadłem również na problem z rzutowaniem. Ale czasami nie jest potrzebne, zastanawiam się, dlaczego? – SamChen

Powiązane problemy