Обнуляемые типы в строго типизированных таблицах / наборах данных - обходные пути? - PullRequest
25 голосов
/ 30 июля 2010

Строго типизированные DataTables поддерживают типы полей «обнуляемые», за исключением того, что конструктор не позволит вам изменить настройку на «разрешать нули» для любых полей типа значений.(то есть: строковые типы допускают обнуляемое значение, а int - нет).

Обходной путь - вызывать IsMyFieldNull () каждый раз, когда вы хотите получить Myfield.Если вы получаете доступ к MyField, когда он содержит ноль, он создает исключение.

Это огромная головная боль, помимо того, что она вызывает много ошибок во время выполнения, когда появление нуля может привести к сбою приложения.Я годами жаловался в Microsoft на это, но каждый новый выпуск Visual Studio по-прежнему не позволяет использовать типы значений, допускающие значение NULL.

Мой вопрос: Кто-нибудь знает какой-нибудь причудливый метод (ы) расширения, который можно использовать, чтобы обойти этот существенный недостаток?

Ответы [ 7 ]

7 голосов
/ 07 декабря 2011

Если вы используете .Net 3.5 или выше, возможно, вам пригодятся следующие расширения: http://msdn.microsoft.com/en-us/library/system.data.datarowextensions.field.aspx

Согласно документации, он полностью поддерживает типы, допускающие обнуление.Он позволяет вам использовать конструкции типа

MyRow.Field<int?>("MyField") 

, и если вы присваиваете его существующей переменной правильного типа или из нее, компилятор может автоматически определить тип, а вы можете опустить спецификатор типа, делая еговсего лишь

int? myVar = MyRow.Field("MyField");
MyRow.Field("MyField") = myVar;

Все еще не идеально, но гораздо более разборчиво, чем необходимость везде использовать IsMyFieldNull () и т. д.

О, и если вы хотите быть более безопасным в отношениинеправильно вводя имена столбцов, вы можете использовать такие вещи, как

MyRow.Field(MyTable.MyFieldColumn)

Не забудьте добавить ссылку на System.Data.DataSetExtensions .

2 голосов
/ 30 июля 2010

В VS 2008 вы можете просто ввести '0' в свойстве nullvalue.
Если вы используете vs2005, вы должны сделать это с помощью редактора XML. Вы должны добавить msprop:nullValue="0" в качестве атрибута к столбцу.

1 голос
/ 30 июля 2010

Я согласен, что было бы неплохо разрешить типы, допускающие обнуление.

Если вы установите для свойства столбца «NullValue» значение «-1» вместо «(исключение выброса)», свойство будет возвращать -1, если столбец равен нулю, а не выбрасывать исключение. Вы все еще должны установить столбец, чтобы разрешить нулевые значения.

Кроме того, вы всегда можете установить тип данных "System.Object" и разрешить nulls = true. Вы можете получить доступ к значению столбца, не используя метод "IsMyFieldNull ()". Значение столбца будет «System.DbNull.Value», когда столбец является нулевым. Если вам не нравится использование «System.DbNull.Value», вы можете установить для свойства «NullValue» значение «(Nothing)» вместо «(исключение Throw)», а затем сравнить объект с нулевой ссылкой.

0 голосов
/ 14 сентября 2016

Мне просто нужно было обойти это.Мне нужно было изменить старый код для веб-страницы, написанный для ASP.NET 2.0.Страница использует Telerik RadMenu, элемент управления меню.Этот компонент требует, чтобы корневые элементы имели правильные значения DBNull (для parentID).Поэтому, когда я компилировал старый код, компонент RadMenu доставил мне много проблем.Первые исключения касались ограничений, потом не понимали, какие элементы были корневыми, и все это выглядело ужасно.

Но я решил это, и это то, что у меня сработало.

На странице свойствстолбца ParentID в конструкторе адаптера таблицы, я использовал: - AllowDBNull: true - DefaultValue: -1 (-1 - значение, которое обычно не встречается в этом столбце) Свойство NullValue осталось в «Исключении выброса», как и былоневозможно изменить для меня.

И в коде, использующем значения из табличного адаптера, я использовал эту конструкцию (код VB.NET, а не C #, поскольку этот вопрос помечен):

Dim MenuBarTable As DAL.Page.MenuBarDataTable 'The Table Adapter
MenuBarTable = PageObj.GetMenuBar()  'The generated Get function 
MenuBarTable.ParentIDColumn.AllowDBNull = True 

    For Each row As Page.MenuBarRow In MenuBarTable.Rows
        If row.IsParentIDNull() Then 
            row.SetParentIDNull() 
        End If
    Next

Код, сгенерированный для адаптеров таблиц, генерирует две функции для каждого столбца, которые должны разрешать DBNULL.Они предназначены для использования с NULL, но это неуклюжее решение Microsoft.За кулисами происходит то, что адаптер таблицы будет выводить столбец DefaultValue вместо NULL из функции Get.Я называю это "имитированным NULL" или "поддельным NULL".

Функция IsParentIDNull () фактически проверит, содержит ли строка этот "поддельный NULL", например, DefaultValue столбца, и когда это произойдет, яЯ вставляю правильный DBNull с помощью функции SetParentIDNull ().

Это решение работает для меня, но не очень элегантно и не очень эффективно, но, надеюсь, может помочь кому-то еще.

0 голосов
/ 25 октября 2013

Вы можете сделать это: установите для параметра AllowDbNull значение true, если оно не установлено; DefaultValue остается включенным; NullValue остается включенным (исключение Броска). Затем из кода, когда вы хотите установить нулевой столбец, вы можете использовать встроенный метод Set_Column_Null (). Посмотри мой пример:

if (entry.PosX.HasValue)
    newRow.PosX = entry.PosX.Value;
else
    newRow.SetPosXNull(); 
0 голосов
/ 04 августа 2010

Я не уверен, почему var x = !IsMyFieldNull() ? MyField : null (или похожая) такая головная боль.

Полагаю, вы могли бы написать обертку вокруг SqlDataReader, чтобы каким-то образом перехватывать эти нулевые значения, когда вы читаете данные в свой DataTable, или вы можете написать эквивалент .TryParse() для ваших запросов: что-то хорошее и инкапсулированное, как:

var x = myDataTable.TryParse(myField);

где .TryParse - это метод расширения, который выглядит примерно так:

public static TryParse(DataRow myField)
{
    if(!myField == DbNull) //Or similar
       return myField.Value;
}

Это, как вы можете видеть, в основном псевдокод грубый, но вы поняли идею. Напишите свой код один раз, а затем вызовите его как метод расширения.

0 голосов
/ 31 июля 2010

Обнуляемые типы были введены в .net 3.0, их можно использовать с наборами данных. Вы объявляете обнуляемый int как этот int? myNullableInt = null Вот ссылка на статью MSDN: Обнуляемые типы C #

Лично я бы в первую очередь держался подальше от нулей в базах данных (если бы у вас была такая возможность). NULL действительно существует для разрешения статуса «Undefined» или «Unknown». Эта проблема возникает редко, например, для поля String, содержащего фамилию, часто устанавливается значение NULL, в то время как значение по умолчанию "" было бы гораздо лучшим вариантом. Помещение пустых значений в базы данных усложняет задачу Нулевые значения в базах данных , кроме того, оно распространяет нулевые значения в коде, и вам нужно работать, чтобы избежать исключений нулевых ссылок.

К сожалению, в Интернете написано много плохих вещей о БД (например, чрезмерное использование нуля как нормального). Эти точки зрения обычно принадлежат людям, которые действительно не понимают теорию, стоящую за ними, еще одним классическим примером является БД без отношений, «потому что это более гибко / быстрее обрабатывать их в коде». Это означает, что разработчик должен переписать существующую функциональность [уровня базы данных], которую неизбежно обрабатывает база данных более эффективно и с гораздо большей надежностью. Я говорю неизбежность, поскольку, разумеется, разработчик, выполняющий переписывание, заново реализует то, что Oracle / Microsoft / Кто-либо, у которого большие команды тратят много времени на оптимизацию и т. Д. Тем не менее, время от времени вы видите, что кто-то выступает за это дизайн. Этот парень действительно понимает базы данных, DBDebunkings , он потратил много времени, пытаясь разоблачить множество бессмысленных нарушений, которые отнимают реляционные базы данных от их теоретических корней.

...