2012-11-19 10 views
55

Mam następujący kod do określania parametrów zapytania SQL. Dostaję następujący wyjątek, gdy używam Code 1; ale działa dobrze, gdy używam Code 2. W Code 2 mamy czek na wartość zerową, a tym samym blok if..else.Wyjątek, gdy parametr AddWithValue ma wartość NULL

Wyjątek

Zapytanie parametryzowane '(@application_ex_id nvarchar (4000)) SELECT E.application_ex_id A' oczekuje parametr '@application_ex_id', który nie został dostarczony.

Kod 1:

command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID); 

Kod 2:

if (logSearch.LogID != null) 
{ 
     command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID); 
} 
else 
{ 
     command.Parameters.AddWithValue("@application_ex_id", DBNull.Value); 
} 

ZAPYTANIE

  1. Czy możesz wyjaśnić, dlaczego nie można pobrać wartości NULL z wartości logSearch.LogID w Kodzie 1 (ale w stanie zaakceptować DBNull)?

  2. Czy jest lepszy kod do obsłużenia tego?

odniesienia:

  1. Assign null to a SqlParameter
  2. Datatype returned varies based on data in table
  3. Conversion error from database smallint into C# nullable int
  4. What is the point of DBNull?

KOD

public Collection<Log> GetLogs(LogSearch logSearch) 
    { 
     Collection<Log> logs = new Collection<Log>(); 

     using (SqlConnection connection = new SqlConnection(connectionString)) 
     { 
      connection.Open(); 

      string commandText = @"SELECT * 
       FROM Application_Ex E 
       WHERE (E.application_ex_id = @application_ex_id OR @application_ex_id IS NULL)"; 

      using (SqlCommand command = new SqlCommand(commandText, connection)) 
      { 
       command.CommandType = System.Data.CommandType.Text; 

       //Parameter value setting 
       //command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID); 
       if (logSearch.LogID != null) 
       { 
        command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID); 
       } 
       else 
       { 
        command.Parameters.AddWithValue("@application_ex_id", DBNull.Value); 
       } 

       using (SqlDataReader reader = command.ExecuteReader()) 
       { 
        if (reader.HasRows) 
        { 
         Collection<Object> entityList = new Collection<Object>(); 
         entityList.Add(new Log()); 

         ArrayList records = EntityDataMappingHelper.SelectRecords(entityList, reader); 

         for (int i = 0; i < records.Count; i++) 
         { 
          Log log = new Log(); 
          Dictionary<string, object> currentRecord = (Dictionary<string, object>)records[i]; 
          EntityDataMappingHelper.FillEntityFromRecord(log, currentRecord); 
          logs.Add(log); 
         } 
        } 

        //reader.Close(); 
       } 
      } 
     } 

     return logs; 
    } 
+3

Co masz na myśli przez lepszy? Kod 2 to poprawny sposób wysyłania wartości pustej do bazy danych. –

+0

Odniesienia: http://stackoverflow.com/questions/13265704/conversion-error-from-database-smallint-into-c-sharp-ululble-t – Lijo

Odpowiedz

84

Irytujące, czyż nie?

Można użyć:

command.Parameters.AddWithValue("@application_ex_id", 
     ((object)logSearch.LogID) ?? DBNull.Value); 

Lub alternatywnie, użyj narzędzia takie jak „elegancki”, który zrobi wszystko, brudząc dla Ciebie.

Na przykład:

var data = conn.Query<SomeType>(commandText, 
     new { application_ex_id = logSearch.LogID }).ToList(); 

jestem kuszony dodać metodę Wytworny uzyskać IDataReader ... jeszcze, czy jest to dobry pomysł, pewien.

+0

@Phil indeed; większość rzeczy może ... ale nie lubię dodawać metod rozszerzeń do 'obiektu', i nie możemy zobaczyć, czy jest to' Nullable 'vs' string', etc ... ale tak: można to łatwo zrobić dość. –

+1

Myślałem o rozszerzeniu na własności 'Parameters' - czy jest to' Obiekt'? –

+3

@Phil hmmm, tak jest i widzę co masz na myśli ... może 'AddWithValueAndTreatNullTheRightDamnedWay (...)' –

1

jakiś problem, pozwoliło z Koniecznie ustawić SQLDbType

command.Parameters.Add("@Name", SqlDbType.NVarChar); 
command.Parameters.Value=DBNull.Value 

gdzie SqlDbType.NVarChar wpisywania. Koniecznie ustaw typ SQL. Enjou

34

I łatwiej po prostu napisać metodę rozszerzenia dla SqlParameterCollection który obsługuje wartości null:

public static SqlParameter AddWithNullableValue(
    this SqlParameterCollection collection, 
    string parameterName, 
    object value) 
{ 
    if(value == null) 
     return collection.AddWithValue(parameterName, DBNull.Value); 
    else 
     return collection.AddWithValue(parameterName, value); 
} 

Następnie wystarczy zadzwonić podoba:

sqlCommand.Parameters.AddWithNullableValue(key, value); 
+0

_value_ może mieć wartość ** int lub int ?, string, bool lub bool ?, DateTime lub Datetime? ** itd.? – Kiquenet

+0

@Kiquenet Tak ... – AxiomaticNexus

+2

Przeczytałem odpowiedź Marca i pomyślałem: "Myślę, że wolałbym napisać metodę rozszerzenia dla kolekcji Parameters", a potem przewinąłem włosy ... (fajną rzeczą w metodzie rozszerzenia jest to, że Mogę wykonać pojedyncze wyszukiwanie/zamiany po i wszystkie moje aktualizacje kodu są gotowe). – jleach

2

wszelki wypadek” robienie tego podczas wywoływania procedury składowanej: Myślę, że łatwiej jest odczytać, jeśli zadeklarujesz wartość domyślną parametru i dodasz ją tylko wtedy, gdy będzie to konieczne.

Na przykład: (SQL)

DECLARE PROCEDURE myprocedure 
    @myparameter [int] = NULL 
AS BEGIN 

(C#)

int? myvalue = initMyValue(); 
if (myvalue.hasValue) cmd.Parameters.AddWithValue("myparamater", myvalue); 

Wiem, że to stary, ale uważam, że to pomocny i chciałem podzielić.

-3

Tworzenie statycznej klasy tak:

public static class Extensions 
{ 
    public static string RemoveNulls(this string container) 
    { 
     if (container == null) 
      container = ""; 
     return container; 
    } 
} 

Następnie w kodzie, to zrobić:

Parameters.AddWithValue(sName, Value.RemoveNulls()); 

To kuloodporne i bardzo łatwy w użyciu

+1

Zostanie wstawiony znak "", a nie pusty ... – Lars

+0

Tego właśnie chce - nie wpisywać wartości zerowej – TheWizardOfTN

Powiązane problemy