Возможно ли объединить строку и DBNull в C #? - PullRequest
10 голосов
/ 09 октября 2009

Я пишу подпрограмму C # для вызова хранимого процесса. В списке параметров, который я передаю, возможно, что одно из значений по закону может быть нулевым. Поэтому я решил использовать такую ​​строку:

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

К сожалению, это возвращает следующую ошибку:

CS0019: оператор '??' не может применяться к операндам типа 'string' и 'System.DBNull'

Теперь, это кажется достаточно ясным, но я не понимаю обоснования этого. Почему бы это не сработало? (И часто, когда я не понимаю, почему что-то не работает, это не значит, что это не может работать ... это то, что я делаю это неправильно.)

Неужели мне действительно нужно растянуть это в более длинное выражение "если тогда"?

РЕДАКТИРОВАТЬ: (В дополнение к этому, для тех, кто предлагает просто использовать «null», как есть, это не работает. нет. (Кто знал?))

Ответы [ 10 ]

16 голосов
/ 09 октября 2009

Не так, нет. Типы должны совпадать. То же самое относится и к троичной.

Теперь, под словом "матч", я не имею в виду, что они должны быть одинаковыми. Но они должны быть совместимы по назначению. В основном: в том же дереве наследования.

Один из способов обойти это - привести вашу строку к объекту:

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

Но мне это не нравится, потому что это означает, что вы больше полагаетесь на конструктор SqlParameter для получения правильных типов. Вместо этого мне нравится делать это так:

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; 
}

Обратите внимание, что я явно объявил тип параметра.

5 голосов
/ 09 октября 2009
new SqlParameter("@theParam", (object)theParam ?? DBNull.Value)
3 голосов
/ 09 октября 2009

Оператор возвращает левый операнд, если он не равен нулю, или возвращает правый операнд. Но в вашем случае они бывают разных типов, так что это не работает.

2 голосов
/ 09 октября 2009

Оператор Null Coalesce только с данными того же типа. Вы не можете отправить NULL в SqlParamater, так как это заставит Sql Server сказать, что вы не указали параметр.

Вы можете использовать

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

Или вы можете создать функцию, которая возвращает DBNull при обнаружении нуля, например

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

А затем позвоните

new SqlParameter("@theParam", GetDataValue(theParam))
2 голосов
/ 09 октября 2009

Причина, по которой вы не можете использовать оператор null coalesce, заключается в том, что он должен возвращать один тип, а вы предоставляете более одного типа. theParam это строка. DbNull.Value является ссылкой на статический экземпляр типа System.DbNull . Вот как выглядит его реализация;

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

Итак, если бы у вас был метод NullCoalesce, каким был бы его тип возвращаемого значения? Это не может быть как System.String, так и System.DbNull, это должен быть один или другой, или общий родительский тип.

Итак, это приводит к такому типу кода;

cmd.Parameters.Add(
    new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value)
);
1 голос
/ 10 октября 2009

В вашей сохраненной процедуре, когда вы объявляете входящую переменную, задаете для нее переменную равную null, а затем не передаете ее из кода csharp, тогда она получит значение по умолчанию из sql

@theParam as varchar(50) = null

а затем в вашем csharp

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

Именно так я обычно передаю значения опций и / или значения по умолчанию для моих сохраненных процедур

0 голосов
/ 10 октября 2009

Используйте этот синтаксис:

(theParam как объект) ?? (DBNull.Value как объект)

В этом случае обе части оператора ?? одного типа.

0 голосов
/ 09 октября 2009

cmd.Parameters.Add (новый SqlParameter ("@ theParam", (theParam == null)? DBNull.Value: theParam));

0 голосов
/ 09 октября 2009

Не уверен, что конкретный ответ на ваш вопрос, но как насчет этого?

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

или если пусто в порядке

(theParam == null) ? DBNull.Value : theParam
0 голосов
/ 09 октября 2009

Я почти уверен, что просто передача нулевого значения конструктору SqlParameter приводит к его отправке в виде DBNull.Value ... Я могу ошибаться, поскольку я использую EnterpriseLibraries для доступа к БД, но я совершенно уверен что отправка нуля там хорошо.

...