2010-12-29 20 views
129

Następujący kod zawiera błąd - "Brak niejawnej konwersji z DBnull na int."Przypisywanie wartości null do SqlParameter

SqlParameter[] parameters = new SqlParameter[1];  
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int); 
planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex; 
parameters[0] = planIndexParameter; 
+4

Trzeba rzucić AgeItem.AgeIndex sprzeciwić myślę ... http://stackoverflow.com/questions/202271/why- is-this-code-invalid-in-c (btw, dlaczego '==' na końcu trzeciej linii?) – Greg

Odpowiedz

251

Problem polega na tym, że operator ?: nie może określić typu zwracanego, ponieważ zwracana jest wartość int lub wartość typu DBNull, które nie są zgodne.

Można oczywiście rzucić wystąpienie AgeIndex na typ object, który spełni wymagania ?:.

Można użyć operatora ?? null koalescencyjny następująco

SqlParameter[] parameters = new SqlParameter[1];  
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int); 
planIndexParameter.Value = (object)AgeItem.AgeIndex ?? DBNull.Value; 
parameters[0] = planIndexParameter; 

Oto cytat z MSDN documentation dla operatora ?: z wyjaśnieniem problemu

Albo rodzaj first_expression i second_expression musi być taka sama lub musi istnieć niejawna konwersja z jednego typu na drugi.

+0

Dlaczego czy nie ma wyjątków zgłaszanych przy próbie rzutowania pustej wartości na obiekt? Myślę, że powinien to być "AgeItem.AgeIndex jako obiekt" –

+0

@Niels Brinch, nie byłoby wyjątku, ponieważ null jest obiektem i dopóki nie próbujesz go usunąć, jest to całkowicie legalne. Jednak w tym przykładzie nie jest rzutowany na obiekt null, jest to DBNull.Value, który jest faktycznie typem wartości. The ?? operator mówi "jeśli AgetItem.AgeIndex ma wartość null, a następnie zwróci DBNull.Value inaczej returen AgeItem.AgeIndex", wówczas odpowiedź jest rzutowana na obiekt. Zobacz operator koalescencji zerowej, aby uzyskać więcej szczegółów. http://msdn.microsoft.com/en-us/library/ms173224.aspx –

+3

Z technicznego punktu widzenia, twoje rozwiązanie wykorzystujące operator koalescencyjny "??" jest tym samym rozwiązaniem, co w przypadku używania zwykłego potrójnego '?: '- nadal musisz rzucić' AgeItem.AgeIndex' do obiektu: 'planIndexParameter.Value = AgeItem.AgeIndex.HasValue? (obiekt) AgeItem.AgeIndex: DBNull.Value; '. – newfurniturey

0

Spróbuj tego:

if (AgeItem.AgeIndex != null) 
{ 
    SqlParameter[] parameters = new SqlParameter[1]; 
    SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int); 
    planIndexParameter.Value = AgeItem.AgeIndex; 
    parameters[0] = planIndexParameter; 
} 

Innymi słowy, jeśli parametr ma wartość null prostu nie wysłać go do przechowywanej proc (zakładając oczywiście, że składowany proc akceptuje parametry zerowe, które jest implicite w twoim pytaniu).

+0

Ale teraz, po prostu pomijasz parametr - bardzo wątpię, że procedura przechowywana będzie szczęśliwa o tym .... najprawdopodobniej połączenie nie powiedzie się "brak wartości dla parametru @AgeIndex dostarczone, co było oczekiwane" ..... –

+0

Wow. Szorstki. Po prostu zapisz przechowywany proc domyślnie na wartość, jeśli parametr nie zostanie przekazany (@AgeIndex int = 0). Dzieje się cały czas. Klient może zaakceptować wartość domyślną lub przesłonić ją, przekazując parametr. Dlaczego upadek? – Flipster

1

Moim zdaniem lepiej jest to zrobić z nieruchomości Parameters klasy SqlCommand:

public static void AddCommandParameter(SqlCommand myCommand) 
{ 
    myCommand.Parameters.AddWithValue(
     "@AgeIndex", 
     (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex); 
} 
+0

Ale jeśli wartością jest "DBNull.Value", ADO.NET może mieć pewne trudności z odgadnięciem, co SqlDbType może być ........ jest to wygodne - ale nieco niebezpieczne .... –

18

Trzeba zdać DBNull.Value jako parametr null w SQLCommand, chyba że wartość domyślna jest określona w terminie procedura składowana (jeśli używana jest procedura składowana). Najlepszym rozwiązaniem jest przypisanie wartości DBNull.Value do dowolnego brakującego parametru przed wykonaniem zapytania, a następnie wykonaj polecenie foreach.

foreach (SqlParameter parameter in sqlCmd.Parameters) 
{ 
    if (parameter.Value == null) 
    { 
     parameter.Value = DBNull.Value; 
    } 
} 

Inaczej zmienić tę linię:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex; 

W następujący sposób:

if (AgeItem.AgeIndex== null) 
    planIndexParameter.Value = DBNull.Value; 
else 
    planIndexParameter.Value = AgeItem.AgeIndex; 

Ponieważ nie można użyć innego rodzaju wartości w rachunku warunkowego, jak DBNull i int różnią się od wzajemnie. Mam nadzieję, że to pomoże.

5

Spróbuj tego:

SqlParameter[] parameters = new SqlParameter[1];  
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int); 

planIndexParameter.IsNullable = true; // Add this line 

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex== ; 
parameters[0] = planIndexParameter; 
0

spróbować czegoś takiego:

if (_id_categoria_padre > 0) 
{ 
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre; 
} 
else 
{ 
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value; 
} 
63

The accepted answer sugeruje wykorzystanie gipsie. Jednak większość typów SQL ma specjalne pole NULL, którego można użyć do uniknięcia tego rzutowania.

Na przykład SqlInt32.Null "Reprezentuje DBNull, który można przypisać do tego wystąpienia klasy SqlInt32."

int? example = null; 
object exampleCast = (object) example ?? DBNull.Value; 
object exampleNoCast = example ?? SqlInt32.Null; 
+2

Sugestia wyglądała obiecująco, więc próbowałem "System.Data.SqlTypes.SqlString.Null", ale to nie działa. Wstawia rzeczywisty ciąg "Null" ("N", "u", "l", "l") do pola zamiast pozostawić puste z prawdą (null). Jednak stara "zaakceptowana odpowiedź" z 2010 r. Używa obsady (obiektu) ?? DBNull.Value działa poprawnie. (Dostawca ADO.NET użyłem SQLite, ale nie jestem pewien, czy to robi różnicę.) Proponuję, aby inni dokładnie przetestowali wskazówkę Briana, aby upewnić się, że zachowanie zerowe działa zgodnie z oczekiwaniami. – JasDev

+4

@JasDev: Niejasno przypominam sobie opisywanie tej sztuczki w komentarzu do użytkownika o wysokim rypsie (myślę, że Marc Gravell) i mówienie, że działa tylko na Microsoft SQL Server. – Brian

+0

@JasDev dostawca będzie różnicą, która działa w SQL Server jako punkt Brain jest obecnie. – Lankymart

0
int? nullableValue = null; 
object nullableValueDB 
{ 
    get{ 
     if(nullableValue==null) 
      return DBNull.Value; 
     else 
      return (int)nullableValue; 
    } 
} 

jestem rozwiązywania takiego.

0
if (_id_categoria_padre > 0) 
{ 
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre; 
} 
else 
{ 
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value; 
} 
0
if (AgeItem.AgeIndex== null) 
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = DBNull); 
else 
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = AgeItem.AgeIndex); 
1

Rozważ użycie strukturę pustych (T) nie jest dostępna. Będzie to niech ustawić tylko wartości, jeśli je masz , a obiekty poleceń SQL rozpoznają wartość zerową i będą przetwarzać je bez żadnych problemów.

0

Po prostu to robię ...

 var PhoneParam = new SqlParameter("@Phone", DBNull.Value); 
     if (user.User_Info_Phone != null) 
     { 
      PhoneParam.SqlValue = user.User_Info_Phone; 
     } 

     return this.Database.SqlQuery<CustLogonDM>("UpdateUserInfo @UserName, @NameLast, @NameMiddle, @NameFirst, @Address, @City, @State, @PostalCode, @Phone", 
      UserNameParam, NameLastParam, NameMiddleParam, NameFirstParam, AddressParam, CityParam, StateParam, PostalParam, PhoneParam).Single(); 
0
  dynamic psd = DBNull.Value; 

      if (schedule.pushScheduleDate > DateTime.MinValue) 
      { 
       psd = schedule.pushScheduleDate; 
      } 


      sql.DBController.RunGeneralStoredProcedureNonQuery("SchedulePush", 
        new string[] { "@PushScheduleDate"}, 
        new object[] { psd }, 10, "PushCenter"); 
1

Jeśli używasz warunkowy (potrójny) operator kompilator potrzebuje niejawna konwersja między obu typów, inaczej dostaniesz wyjątek.

więc można go naprawić, oddając jedną zarówno System.Object:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : (object) AgeItem.AgeIndex; 

Ale ponieważ wynik nie jest naprawdę ładna i zawsze trzeba pamiętać to odlew, można użyć takiego metodę rozszerzenia zamiast:

public static object GetDBNullOrValue<T>(this T val) 
{ 
    bool isDbNull = true; 
    Type t = typeof(T); 

    if (Nullable.GetUnderlyingType(t) != null) 
     isDbNull = EqualityComparer<T>.Default.Equals(default(T), val); 
    else if (t.IsValueType) 
     isDbNull = false; 
    else 
     isDbNull = val == null; 

    return isDbNull ? DBNull.Value : (object) val; 
} 

Następnie można użyć tego kodu zwięzły:

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue(); 
0

Prosta metoda rozszerzenia tego:

public static void AddParameter(this SqlCommand sqlCommand, string parameterName, 
     SqlDbType sqlDbType, object item) 
    { 
     sqlCommand.Parameters.Add(parameterName, sqlDbType).Value = item ?? DBNull.Value; 
    } 
0

Coś nie tak z po prostu utworzyć parametr "zerowy" zrobić?

public SqlParameter GetNullableParameter(string parameterName, object value) 
    { 
     if (value == null) 
     { 
      return new SqlParameter(parameterName, value); 
     } 
     else 
     { 
      return new SqlParameter(parameterName, DBNull.Value); 
     } 
    } 
8

Z jednej linii kodu, spróbuj tego:

var piParameter = new SqlParameter("@AgeIndex", AgeItem.AgeIndex ?? (object)DBNull.Value); 
Powiązane problemy