C #: как создать поле базы данных типа guid с нулевым значением для локальной переменной?

У меня есть с одной стороны база данных Access, где Tbl_Application.id_connexion - это поле с типом Guid (называемым «идентификатором репликации» в терминологии ms Access).

Я собираю некоторые данные из этой таблицы Tbl_Application через массив DataRow [] , dr_Tbl_Application . Следующий код считывает первый DataRow:

private Guid? mid_connexion = null;
mid_connexion = (Guid)dr_Tbl_Application[0]["id_connexion"]

Все нормально, если Tbl_Application.id_connexion содержит значение. Если это поле не содержит значения, я получу следующую ошибку:

InvalidCastException was unhandled

И это некоторые вещи, которые я вижу в ближайшем окне:

? dr_Programme[0]["id_Connexion"]
{}

? dr_Programme[0]["id_Connexion"].GetType()
{Name = "DBNull" FullName = "System.DBNull"}

? dr_Programme[0]["id_Connexion"] is System.DBNull
true

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

Мои вопросы заключаются в следующем:

  1. Есть ли способ написать некоторый базовый код, чтобы назначить значение из значения базы данных Guid для локального объекта Guid без проверки на System.DBNull ?
  2. Почему одна и та же инструкция, применяемая к одному и тому же объекту, возвращает разные типы, в зависимости от того, находятся ли исходные поля или нет?

Редактировать по вопросу 2:

? dr_Programme[0]["id_Connexion"].GetType()

возвращает тип System.Guid, когда соответствующее поле заполняется в исходной таблице, тогда как

? dr_Programme[0]["id_Connexion"].GetType()

возвращает тип System.DBNull, когда поле имеет нулевое значение (или не заполнено) в исходной таблице ...

4
nl ja de
Это уже обсуждалось в аналогичном вопрос здесь
добавлено автор Steve, источник
@Syneryx Это не работает. System.DBNull нельзя передать в Nullable .
добавлено автор Hamlet Hakobyan, источник
вы пробовали mid_connexion = (Guid?) dr_Tbl_Application [0] ["id_connexion"] отметить? обозначить его как нулевое Guid, как вы это делали с вашим mid_connexion. При вызове (Guid) dr_Tbl_Application [0] ["id_connexion"] будет пытаться присвоить значение null типу GUID, который не является типом NULL.
добавлено автор Syneryx, источник
@HamletHakobyan мой плохой. но, похоже, у Мортена Мертнера есть ответ.
добавлено автор Syneryx, источник

3 ответы

DBNull implements the Null Object Design Pattern to address the difference between DB returning a NULL vs. not returning anything. Unfortunately, the lack of its intuitiveness keeps tripping up programmers for many years.

Лучшее, что вы можете сделать, это обернуть его в общий метод, например:

public static T? GetNullable(object obj) where T : struct
{
    if (obj == DBNull.Value) return null;
    return (T?)obj;
}

Теперь вы можете вызвать этот метод следующим образом:

mid_connexion = GetNullable(dr_Tbl_Application[0]["id_connexion"]);
4
добавлено
Спасибо за ссылки!
добавлено автор Philippe Grondier, источник

Я боюсь, что вам придется продолжать проверять DBNull, если вы не разработаете схему БД, чтобы не допустить их возникновения. Также обратите внимание, что DBNull отличается от C# null.

Вероятно, вы можете сделать код немного менее подробным, используя класс Convert в C #. В общем случае он будет выполнять преобразования по умолчанию вместо того, чтобы генерировать исключение (например, когда он встречается с нулевым значением, обратите внимание, что я не знаю, как справляться с значениями DBNull, поэтому вам придется иметь дело с ними вручную).

Моя рекомендация заключалась бы в создании набора методов расширения для выполнения необходимой работы:

public static class AccessExtensions
{
    public static Guid GetGuidOrEmpty( this IDbReader reader, string columnName )
    {
       //all the code to check for DBNull and conversions goes here
       //...

        return hasValue ? value : Guid.Empty;
    }
}

Одним из последних слов предостережения является то, что Access может быть забавным относительно GUID, например, требуя строк для вставки/обновления, но возвращающих типы GUID при выборе. Возможно, это улучшилось с тех пор, как я попробовал это в 2003 году или около того.

1
добавлено
Руководство по управлению между таблицами Access и Access vba и \ или другим кодом vb всегда было настоящим PITA ...
добавлено автор Philippe Grondier, источник

Использовать это:

public static class SomeClass
    {
        public static Guid? With(this Guid? o, object x)
        {
            if (x is System.DBNull) return null;
            return o = (Guid)x;
        }
    }
1
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot