Сведения о вопросе

Ислам

22:28, 15th August, 2020

Теги

c#   .net   sql-server    

Как лучше всего бороться с DBNull-Ми

Просмотров: 554   Ответов: 14

У меня часто возникают проблемы, связанные с DataRows возвращением из SqlDataAdapters . Когда я пытаюсь заполнить объект с помощью такого кода:

DataRow row = ds.Tables[0].Rows[0];
string value = (string)row;

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



  Сведения об ответе

PROGA

05:39, 18th August, 2020

Nullable типы хороши, но только для типов, которые изначально не являются nullable.

Чтобы создать тип "nullable", добавьте к нему вопросительный знак, например:

int? value = 5;

Я бы также рекомендовал использовать ключевое слово "as"вместо приведения. Вы можете использовать ключевое слово "as" только для nullable типов, поэтому убедитесь, что вы создаете вещи, которые уже являются nullable (например, строки) или используете nullable типы, как указано выше. Рассуждение для этого

  1. Если тип является nullable, ключевое слово " as " возвращает null , если значение равно DBNull .
  2. Это ever-so-slightly быстрее, чем кастинг , хотя только в некоторых случаях . Это само по себе никогда не является достаточно хорошей причиной для использования as , но в сочетании с приведенной выше причиной это полезно.

Я бы рекомендовал сделать что-то вроде этого

DataRow row = ds.Tables[0].Rows[0];
string value = row as string;

В приведенном выше случае, если row возвращается как DBNull, то value станет null вместо того, чтобы создавать исключение. Имейте в виду, что если ваш запрос DB изменяет возвращаемые столбцы/типы, то использование as приведет к молчаливому сбою кода и сделает значения простыми null вместо того, чтобы создавать соответствующее исключение при возврате неверных данных, поэтому рекомендуется использовать тесты для проверки ваших запросов другими способами, чтобы обеспечить целостность данных по мере развития вашей кодовой базы.


  Сведения об ответе

SEEYOU

19:37, 24th August, 2020

Если вы не используете nullable типы, лучше всего проверить, является ли значение столбца DBNull. Если это DBNull, то установите ссылку на то, что вы используете для null/пустой для соответствующего типа данных.

DataRow row = ds.Tables[0].Rows[0];
string value;

if (row["fooColumn"] == DBNull.Value)
{
   value = string.Empty;
}
else 
{
   value = Convert.ToString(row["fooColumn"]);
}

Как сказал Ману, вы можете создать класс convert с перегруженным методом convert для каждого типа, поэтому вам не нужно перчить свой код блоками if/else.

Однако я подчеркну, что nullable types-это лучший маршрут, если вы можете их использовать. Рассуждение состоит в том, что с ненулевыми типами вам придется прибегнуть к "magic numbers", чтобы представить null. Например, если вы сопоставляете столбец с переменной int, как вы собираетесь представить DBNull? Часто вы не можете использовать 0, потому что 0 имеет допустимое значение в большинстве программ. Часто я вижу, как люди сопоставляют DBNull с int.MinValue,но это тоже может быть проблематично. Мой лучший совет таков:

  • Для столбцов, которые могут быть null в базе данных, используйте типы nullable.
  • Для столбцов, которые не могут быть null в базе данных, используйте обычные типы.

Для решения этой проблемы были созданы типы, допускающие обнуление. Тем не менее, если вы находитесь на более старой версии фреймворка или работаете на кого-то, кто не использует grok nullable types, пример кода сделает свое дело.


  Сведения об ответе

piter

12:58, 15th August, 2020

Добавьте ссылку на System.Data.DataSetExtensions, которая добавляет поддержку Linq для запроса таблиц данных.

Это было бы что-то вроде:

string value = (
    from row in ds.Tables[0].Rows
    select row.Field<string>(0) ).FirstOrDefault();


  Сведения об ответе

lesha

16:48, 28th August, 2020

Я всегда находил его ясным, кратким и без проблем использующим версию проверки If/Else, только с тернарным оператором. Сохраняет все в одной строке, включая присвоение значения по умолчанию, если столбец имеет значение null.

Итак, предположим, что nullable Int32 столбец с именем "MyCol", где мы хотим вернуть -99, если столбец null, но возвращаем целое значение, если столбец не null:

return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]);

Это тот же метод, что и у победителя If / Else выше , но я обнаружил, что если Вы читаете несколько столбцов из datareader, это настоящий бонус, когда все строки для чтения столбцов расположены друг под другом, выстроившись в ряд, так как легче обнаружить ошибки:

Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]);
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]);
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]);


  Сведения об ответе

DINO

12:51, 25th August, 2020

Если у вас есть контроль над запросом, который возвращает результаты, вы можете использовать ISNULL() для возврата значений, отличных от null, например:

SELECT 
  ISNULL(name,'') AS name
  ,ISNULL(age, 0) AS age
FROM 
  names

Если ваша ситуация допускает, что эти магические значения заменяют NULL, такой подход может устранить проблему во всем вашем приложении, не загромождая ваш код.


  Сведения об ответе

davran

03:12, 7th August, 2020

DBNull орудия труда .ToString() как и все остальное. Не нужно ничего делать. Вместо жесткого броска вызовите объект .ToString() метод.

DataRow row = ds.Tables[0].Rows[0];
string value;

if (row["fooColumn"] == DBNull.Value)
{
   value = string.Empty;
}
else 
{
   value = Convert.ToString(row["fooColumn"]);
}

это становится:

DataRow row = ds.Tables[0].Rows[0];
string value = row.ToString()

DBNull.ToString() возвращает string.Empty

Я бы предположил, что это лучшая практика, которую вы ищете


  Сведения об ответе

PAGE

18:07, 18th August, 2020

Стоит отметить, что DBNull.Value.ToString() равно String.Empty

Вы можете использовать это в своих интересах:

DataRow row = ds.Tables[0].Rows[0];
string value = row["name"].ToString();

Однако это работает только для строк, для всего остального я бы использовал путь linq или метод расширения. Для себя я написал небольшой метод расширения, который проверяет DBNull и даже делает кастинг через Convert.ChangeType(...)

int value = row.GetValueOrDefault<int>("count");
int value = row.GetValueOrDefault<int>("count", 15);


  Сведения об ответе

SILA

12:32, 4th August, 2020

Часто при работе с DataTables вам приходится иметь дело с такими случаями, когда поле строки может быть либо null, либо DBNull, обычно я имею дело с этим так:

string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty;

Оператор 'as' возвращает null для недопустимых приведений, например DBNull в строку, и '??' возвращает термин справа от выражения, если первым является null.


  Сведения об ответе

crush

21:49, 5th August, 2020

Брэд Абрамс опубликовал что-то связанное всего пару дней назад http://blogs.msdn.com/brada/archive/2009/02/09/framework-design-guidelines-system-dbnull.aspx

В итоге "AVOID использует System.DBNull. Вместо этого предпочтите Nullable."

А вот мои два цента (непроверенного кода :) )

// Or if (row["fooColumn"] == DBNull.Value)
if (row.IsNull["fooColumn"])
{
   // use a null for strings and a Nullable for value types 
   // if it is a value type and null is invalid throw a 
   // InvalidOperationException here with some descriptive text. 
   // or dont check for null at all and let the cast exception below bubble  
   value = null;
}
else
{
   // do a direct cast here. dont use "as", "convert", "parse" or "tostring"
   // as all of these will swallow the case where is the incorect type.
   // (Unless it is a string in the DB and really do want to convert it)
   value = (string)row["fooColumn"];
}

И еще один вопрос... Есть ли причина, по которой вы не используете ORM?


  Сведения об ответе

P_S_S

13:58, 3rd August, 2020

Обычно я пишу свой собственный класс ConvertDBNull, который обертывает встроенный класс Convert. Если значение равно DBNull, то он вернет null, если это ссылочный тип, или значение по умолчанию, если это тип значения. Пример: - ConvertDBNull.ToInt64(object obj) возвращает Convert.ToInt64(obj) , если obj не является DBNull, и в этом случае он возвращает 0.


  Сведения об ответе

lats

16:21, 7th August, 2020

По какой-то причине у меня возникли проблемы с проверкой по DBNull.Value, поэтому я сделал вещи немного иначе и использовал свойство в объекте DataRow:

if (row.IsNull["fooColumn"])
{
   value = string.Empty();
}
{
else
{
   value = row["fooColumn"].ToString;
}


  Сведения об ответе

LIZA

06:47, 27th August, 2020

Вы также можете проверить с помощью Convert.IsDBNull (MSDN) .


  Сведения об ответе

9090

10:46, 7th August, 2020

Вы также должны посмотреть на методы расширения. Вот несколько примеров, чтобы иметь дело с этим scenerio.

Рекомендуется читать


  Сведения об ответе

SKY

11:05, 16th August, 2020

Если вы заинтересованы в получении DBNull при ожидании строк, один из вариантов заключается в преобразовании всех значений DBNull в DataTable в пустую строку.

Это довольно просто сделать, но это добавит некоторые накладные расходы, особенно если вы имеете дело с большими DataTables. Проверьте эту ссылку , которая показывает, как это сделать, если вы заинтересованы


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться