2009-10-09 10 views
10

Piszę procedurę C#, aby wywołać przechowywany proc. Na liście parametrów, które mijam, jest możliwe, że jedna z wartości może być prawnie zerowa. Więc pomyślałem, że mogę użyć linię:Czy jest możliwe, aby połączyć ciąg i DBNull w C#?

cmd.Parameters.Add(new SqlParameter("@theParam", theParam ?? DBNull.Value)); 

Niestety, ten zwraca następujący błąd:

CS0019: Operator '??' cannot be applied to operands of type 'string' and 'System.DBNull'

Teraz to wydaje się dość oczywiste, ale nie rozumiem Uzasadnieniem to. Dlaczego to nie zadziałało? (I często, gdy nie rozumiem, dlaczego coś nie działa, to nie jest tak, że nie może działać ... to, że robię to źle.)

Czy naprawdę muszę się rozciągać to na dłuższe stwierdzenie, jeśli-to?

EDIT:.. (Tak na marginesie, do tych, co sugeruje, wystarczy użyć „null”, jak jest, to nie działa pierwotnie zorientowali zerowy będzie automatycznie tłumaczone na DBNull też, ale to najwyraźniej nie (Kto wiedział?))

Odpowiedz

16

Nie tak, nie. Typy muszą się zgadzać. To samo dotyczy trójskładnikowego.

Teraz, przez "mecz", nie mam na myśli, że muszą być takie same. Ale muszą być kompatybilne z przypisaniem. Zasadniczo: w tym samym drzewie dziedziczenia.

Jednym ze sposobów, aby ominąć to oddać swój ciąg do obiektu:

var result = (object)stringVar ?? DBNull.Value; 

Ale nie podoba mi się to, ponieważ oznacza to, jesteś opierając się bardziej na konstruktora SqlParameter aby uzyskać rodzaje prawo . Zamiast tego chciałbym zrobić to tak:

cmd.Parameters.Add("@theParam", SqlDbTypes.VarChar, 50).Value = theParam; 
// ... assign other parameters as well, don't worry about nulls yet 

// all parameters assigned: check for any nulls 
foreach (var p in cmd.Parameters) 
{ 
    if (p.Value == null) p.Value = DBNull.Value; 
} 

Należy również zauważyć, że wyraźnie oświadczył typ parametru.

+0

Aby uzyskać informacje, polecenia utworzone przez CommandBuilder mają zestaw parametrów zbudowanych dla ciebie. Jednak ten sam problem pojawia się w tym, że nie można po prostu oczekiwać przekazania wartości null do jednego z parametrów w wygenerowanym ParameterCollection. nadal musisz postępować zgodnie z powyższym opisem. – rohancragg

+0

Ładne proste rozwiązanie :-) – IrishChieftain

+0

Można również utworzyć metodę rozszerzenia, aby to zrobić. –

0

Jestem prawie pewny, że właśnie przekazanie wartości zerowej do konstruktora SqlParameter powoduje wysłanie go jako DBNull.Value ... Mogę się mylić, ponieważ korzystam z bibliotek Enterprise dla dostępu DB, ale jestem całkiem pewien, że wysłanie wartości zerowej jest w porządku.

+2

Tak, mylisz się, -1. Próba przekazania hasła null spowoduje, że serwer SQL poda błąd "parametr ... nie istnieje". – erikkallen

+0

Erich, przypuszczam, że masz rację, ponieważ zaobserwowałem zachowanie, które opisujesz wiele razy w VB.NET. Pomijając fakt, że to jest C#, nie wiem, jakie są inne okoliczności, które pozwalają mi pracować, a nie erikkallen czy Beska. –

+0

Ah, zwykle używam klasy SqlHelper i właśnie znalazłem tę linię wewnątrz: Jeśli (p.Direction = ParameterDirection.InputOutput OrElse p.Direction = ParameterDirection.Input) AndAlso p.Value Is Nothing Then p.Value = DBNull .Value End If ... Właśnie dlatego działa. –

-1

Nie jestem pewien konkretnej odpowiedzi na twoje pytanie, ale co z tym?

string.IsNullOrEmpty(theParam) ? DBNull.Value : theParam 

lub jeżeli puste jest ok

(theParam == null) ? DBNull.Value : theParam 
+1

Nitternary wymaga również dopasowania typów. –

+0

D'oh! To nauczy mnie post-before-test! – n8wrl

5
new SqlParameter("@theParam", (object)theParam ?? DBNull.Value) 
+0

Nie musisz nawet rzucać obu na zero. Zwykle robię nowy SqlParameter ("@ theParam", (obiekt) theParam? DBNull.Value) – erikkallen

3

?? operator zwraca lewy operand, jeśli nie jest zerowy, lub zwraca prawy operand. Ale w twoim przypadku są to różne typy, więc to nie działa.

+0

(nieistotna edycja wykonana tak, że pozwoliłaby mi głosować na tę odpowiedź.) – Beska

0

cmd.Parameters.Add (nowy SqlParameter ("@ theParam", (theParam == null)? DBNull.Value: theParam));

2

Powód, dla którego nie można użyć operatora koalescencji zerowej, polega na tym, że musi on zwrócić jeden typ i dostarcza więcej niż jeden typ. theParam to ciąg znaków. DbNull.Value to odwołanie do instancji statycznej typu System.DbNull. Tak wygląda jego implementacja;

public static readonly DBNull Value = new DBNull(); 
//the instantiation is actually in the 
//static constructor but that isn't important for this example 

Więc jeśli miałbyś mieć metodę NullCoalesce, jaki byłby jej typ zwrotu? Nie może to być zarówno System.String, jak i System.DbNull, musi to być jeden lub drugi lub wspólny typ nadrzędny.

To prowadzi do tego rodzaju kodu;

cmd.Parameters.Add(
    new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value) 
); 
2

Operator z zerową koalescencją tylko z danymi tego samego typu. Nie możesz wysłać NULL do SqlParamater, ponieważ spowoduje to, że serwer Sql powie, że nie określiłeś parametru.

Można użyć

new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value) 

Lub można utworzyć funkcję, która powrotu DBNull gdy zerowy zostanie znaleziony, jak

public static object GetDataValue(object o) 
{ 
    if (o == null || String.Empty.Equals(o)) 
     return DBNull.Value; 
    else 
     return o; 
} 

a następnie zadzwonić

new SqlParameter("@theParam", GetDataValue(theParam)) 
+4

Tak, metoda GetDataValue polega na tym, jak sobie z tym poradziłem w przeszłości. Naprawdę chciałbym mieć wbudowane zachowanie. Podobnie jak właściwość, którą możesz określić na klasach ADO.NET, która zastąpi DBNULL.Value (lub coś, co określisz), gdy uzyska wartość pustą. – LoveMeSomeCode

+0

Tak, ja też chciałbym móc określić wartość null i pozwolić mu automatycznie mapować do DBNull. –

+0

@LoveMe: Policz mnie, bo to powinno być obsługiwane domyślnie! –

0

użyć następującej składni:

(theParam jako obiekt)? (DBNull.Value jako obiekt)

W tym przypadku obie części operatora? są tego samego typu.

+0

1) Wystarczy rzucić jedną stronę, obie są przesadne; 2) Używanie 'as', dopóki nie przejdziesz do sprawdzenia wartości zwracanej rzutowania (tzn. Jako typwitchwingu) jest złym pomysłem - normalna obsada komunikuje cel bardziej wyraźny. –

1

W swojej przechowywanych proc kiedy zadeklarować zmienną przychodzące mają to ustawienie var równa null i potem nie przechodzą go z kodu CSharp, to wtedy podnieść wartość domyślną z SQL

@theParam as varchar(50) = null 

a następnie w CSharp

if (theParam != null) 
    cmd.Parameters.Add(new SqlParameter("@theParam", theParam)); 

to jest jak zwykle przechodzą opcję i/lub wartości domyślnie moich przechowywanych proca

+0

Myślę, że miałeś na myśli "! =", Naprawiłeś próbkę. –

+0

tak, dziękuję. Zauważyłem to, gdy próbowałem uruchomić blok kodu i zapomniałem wrócić do edycji. –

Powiązane problemy