Работа с DBNull.Value - PullRequest
       6

Работа с DBNull.Value

10 голосов
/ 17 августа 2010

Мне часто приходится иметь дело с таблицами DataTable, связанными с элементами управления сеткой, при пользовательском обновлении всегда создается много кода, связанного с DBNull.Value. Я видел подобный вопрос здесь, но думаю, что должен быть лучший ответ:

Как лучше всего справиться с DBNull's

Я обнаружил, что я склонен инкапсулировать обновления своей базы данных в методы, поэтому в итоге получаю код, подобный приведенному ниже, где я перемещаю DBNull.value в тип NULL, а затем обратно для обновления:

private void UpdateRowEventHandler(object sender, EventArgs e)
{
    Boolean? requiresSupport = null;
    if (grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) != DBNull.Value)
        requiresSupport = (bool)grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport);

    AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport)
}

internal static void UpdateASRecord(
        string year,
        string studentID,            
        bool? requiresSupport)
    {
        List<SqlParameter> parameters = new List<SqlParameter>();

        parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year });
        parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID });

        if (requiresSupport == null)
            parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = DBNull.Value });
        else
            parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = requiresSupport });

        //execute sql query here to do update
    }

Это был просто пример потока, а не рабочего кода. Я понимаю, что мог бы делать такие вещи, как передавать объекты или глотать потенциальные проблемы приведения, используя «как тип», чтобы получить DBUll прямо к нулю, но мне кажется, что оба они скрывают потенциальные ошибки, мне нравится безопасность типов метода с обнуляемыми типами.

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

Ответы [ 4 ]

16 голосов
/ 17 августа 2010

Пара (очень) простых универсальных вспомогательных методов может по крайней мере сконцентрировать тест в один фрагмент кода:

static T FromDB<T>(object value)
{
    return value == DBNull.Value ? default(T) : (T)value;
}

static object ToDB<T>(T value)
{
    return value == null ? (object) DBNull.Value : value;
}

Эти методы могут затем использоваться там, где это необходимо:

private void UpdateRowEventHandler(object sender, EventArgs e)
{
    AdditionalSupport.UpdateASRecord(year, studentID, 
        FromDB<Boolean?>(grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport)));
}

internal static void UpdateASRecord(
        string year,
        string studentID,
        bool? requiresSupport)
{
    List<SqlParameter> parameters = new List<SqlParameter>();

    parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year });
    parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID });
    parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = ToDB(requiresSupport) });

    //execute sql query here to do update
}
1 голос
/ 17 августа 2010

Я не вижу, что не так с as -кастингом и null слиянием.

as -кастинг используется для чтения:

bool? requiresSupport =
  grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?;
AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport);

nullдля записи используется коалесцирование:

parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11)
  { Value = studentID });
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit)
  { Value = (object)requiresSupport ?? DBNull.Value });

Оба эти типа полностью безопасны и не «скрывают» ошибок.

Если вы действительно хотите, вы можете обернуть ихв статические методы, так что вы в конечном итоге с этим для чтения:

//bool? requiresSupport =
//  grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?;
bool? requiresSupport = FromDBValue<bool?>(
  grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport));

и это для записи:

//parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit)
//  { Value = (object)requiresSupport ?? DBNull.Value });
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit)
  { Value = ToDBValue(requiresSupport) });

Код статического метода немного чище в случае записи, нонамерение менее ясно (особенно в случае чтения).

0 голосов
/ 09 декабря 2013
public static object DbNullable<T>(T? value) where T : struct
{
    if (value.HasValue)
    {
        return value.Value;
    }
    return DBNull.Value;
}

public static object ToDbNullable<T>(this T? value) where T : struct
{
    return DbNullable(value);
}

Это моя реализация помощника DBNULL.Использование простое:

new SqlParameter("Option1", option1.ToDbNullable())
0 голосов
/ 17 августа 2010
parameters.Add("@requires_support", SqlDbType.Bit).Value = (object)requiresSupport ?? DBNull.Value;

, что означает то же, что и

parameters.Add("@requires_support", SqlDbType.Bit).Value = (requiresSupport != null) ? (object)requiresSupport : DBNull.Value;

или

if (requiresSupport != null)
    parameters.Add("@requires_support", SqlDbType.Bit).Value = requiresSupport 
else
    parameters.Add("@requires_support", SqlDbType.Bit).Value = DBNull.Value;

(для устранения неоднозначности типа требуется дополнительное приведение к объекту)

...