C# ADO.NET: nulls и DbNull-есть ли более эффективный синтаксис?

у меня есть DateTime? что я пытаюсь вставить в поле с помощью DbParameter. Я создаю параметр так:

DbParameter datePrm = updateStmt.CreateParameter();
datePrm.ParameterName = "@change_date";

и тогда я хочу поставить значение DateTime? на dataPrm.Value С учетом nulls.

сначала я думал, что буду умным:

datePrm.Value = nullableDate ?? DBNull.Value;

но это не удается с ошибкой

оператора??'не может применяться к операндам типа 'System.Датавремя?' и - Система.Значение dbnull'

поэтому я думаю, что это работает, только если второй аргумент является ненулевой версией первого аргумента. Тогда я пошел за:

datePrm.Value = nullableDate.HasValue ? nullableDate.Value : DBNull.Value;

но это не работает:

тип условного выражения не может быть определена, поскольку нет неявного преобразования между 'системой.DateTime " и " система.Значение dbnull'

но я не хочу конвертировать между этими типами!

пока единственное, что я могу получить на работу:

if (nullableDate.HasValue)
  datePrm.Value = nullableDate.Value;
else
  datePrm.Value = DBNull.Value;

это действительно единственный способ написать это? Есть ли способ заставить однострочный оператор работать с помощью троичного оператора?

обновление: я действительно не понимаю, почему ?? версия не работает. MSDN говорит:

The ?? оператор возвращает левый операнд, если он не null, иначе возвращает правый операнд.

это именно то, что я хочу!

обновление 2: Ну, в конце концов, это было очевидно:

datePrm.Value = nullableDate ?? (object)DBNull.Value;

6 ответов


Ах-ха! Я нашел еще более эффективное решение, чем @Trebz!

datePrm.Value = nullableDate ?? (object)DBNull.Value;

Если вы используете C# 3.0, вы можете создать метод расширения, чтобы сделать это легко:

public static class DBNullableExtensions
{
    public static object ToDBValue<T>(this Nullable<T> value) where T:struct
    { 
        return value.HasValue ? (object)value.Value : DBNull.Value;
    }
}


class Program
{
    static void Main(string[] args)
    {
        int? x = null;

        Console.WriteLine(  x.ToDBValue() == DBNull.Value );
    }
}

Это будет работать, если вы использовали

datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : DBNull.Value;

Если вы используете SQLServer, то System.Data.SqlTypes пространство имен содержит классы, которые позволяют избежать назойливого типа литья. Например вместо этого:

var val = (object) "abc" ?? DBNull.Value;

можно написать так:

var val = "abc" ?? SqlString.Null;

Я думаю, что ошибка со второй попыткой связана с nullableDate.Значение и DBNull.Значение-это разные типы, и тернарный оператор должен выбрать один тип для возврата в обоих случаях. У меня нет среды, чтобы проверить это, но я думаю, что это должно работать для вас:

datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : (object)DBNull.Value;

Как я это делаю, у меня есть статический класс утилиты, который просто проходит и проверяет, является ли значение параметра нулевым, затем я устанавливаю значение для выполнения DBNull. Я просто делаю это перед тем, как вызвать казнь.