|
Часто при работе с базами данных возникает такая проблема: как хранить данные из полей, которые могут содержать значения NULL, ведь простые типы данных в .NET не могут иметь значение NULL.
Существует большое количество способов сделать это возможным, .NET Framework 2.0 предлагает нам свой способ, основанный на классе Nullable и соответствующей структуры с таким же названием.
Вот список основных свойств и методов данной структуры:
GetValueOrDefault
GetValueOrDefault(T)
Если значение NULL, то данный метод возвращает значение типа по умолчанию или значение, переданное ему в качестве параметра, если же нет, то возвращается значение свойства Value
HasValue
Возвращает True, если переменная не NULL, и False в противном случае
Value
Возвращает значение переменной, если оно NULL, то генерируется исключение InvalidOperationException.
Класс Nullable содержит следующие методы:
Equals (Generic Nullable, Generic Nullable)
Перегруженный метод, который проверяет эквивалентность двух Nullable объектов
Compare
Метод сравнивает два значения Nullable объекта
GetUnderlyingType
Возвращает тип лежащий в основе Nullable.
Немного подробнее о методе Compare.
Данный метод имеет 2 параметра Nullable<T>. Возвращает Integer значение – результат сравнения.
Меньше нуля
Первый параметр – NULL, а второй не NULL или
Значение первого параметра меньше значения второго параметра
Ноль
Оба параметра NULL или
Значения двух параметров совпадают
Больше нуля
Первый параметр не NULL, а второй – NULL или
Значение первого параметра больше значения второго параметра.
Практическое использование класса и структуры Nullable
C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
namespace TestNullable
{
class Program
{
/// <summary>
/// Объявляем структуру для хранения записей из таблицы
/// </summary>
public struct TestNull
{ //Конструктор структуры, который позволяет заполнить все ее поля
public TestNull(int _Id, string _Name, DateTime _DateBegin, DateTime? _DateEnd)
{
id = _Id;
Name = _Name;
DateBegin = _DateBegin;
DateEnd = _DateEnd;
}
//Объявление полей структуры
public int id;
public string Name;
public DateTime DateBegin;
public DateTime? DateEnd; //Объявление Nullable DateTime, так же правильным может считаться объявление public Nullable<DateTime> DateEnd
}
static void Main(string[] args)
{
//Создаем Generic список, который будет содержать записи из таблицы
List<TestNull> Table = new List<TestNull>();
//Подключаемся к базе данных, что бы загрузить данные из таблицы
using (SqlConnection con = new SqlConnection(@"Data Source= nick2005;Initial Catalog=Test;Integrated Security=True"))
{
con.Open();//Открываем соединение
SqlCommand cmd = con.CreateCommand(); //Создаем объект SQL-команды
cmd.CommandText = "select * from users"; //Вносим запрос, который хотим выполнить
SqlDataReader reader = cmd.ExecuteReader(); //Создаем объект для чтения результатов запроса
while (reader.Read()) //Читаем результат
{
//Добавляем записи в наш список
Table.Add(new TestNull(reader.GetInt32(0), reader.GetString(1), reader.GetDateTime(2), reader.IsDBNull(3) ? null : (Nullable<DateTime>)reader.GetValue(3)));
}
con.Close(); //Закрываем соединение
}
//Цикл вывода данных на экран
foreach (TestNull item in Table)
{
Console.WriteLine("ID={0},Name={1},DateBegin={2},DateEnd={3}", item.id, item.Name, item.DateBegin, item.DateEnd.HasValue == false ? "NULL" : item.DateEnd.Value.ToString());
}
Console.ReadKey();
}
}
}
VB.NET
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Data.SqlClient
Namespace TestNullable
Class program
'''<summary>
''' Объявляем структуру для хранения записей из таблицы
''' </summary>
Public Structure TestNull
'Конструктор структуры, который позволяет заполнить все ее поля
Public Sub New(ByVal _Id As Integer, ByVal _Name As String, ByVal _DateBegin As DateTime, ByVal _DateEnd As Nullable(Of DateTime))
Me.id = _Id
Me.Name = _Name
Me.DateBegin = _DateBegin
Me.DateEnd = _DateEnd
End Sub
'Объявление полей структуры
Public DateBegin As DateTime
Public DateEnd As Nullable(Of DateTime) 'Объявление Nullable DateTime
Public id As Integer
Public Name As String
End Structure
Shared Sub Main()
Dim Table As New List(Of TestNull) 'Создаем Generic список, который будет содержать записи из таблицы
'Подключаемся к базе данных что бы загрузить данные из таблицы
Using con As SqlConnection = New SqlConnection("Data Source= nick2005;Initial Catalog=Test;Integrated Security=True")
con.Open() 'Открываем соединение
Dim cmd As SqlCommand = con.CreateCommand 'Создаем объект SQL-команды
cmd.CommandText = "select * from users" 'Вносим запрос, который хотим выполнить
Dim reader As SqlDataReader = cmd.ExecuteReader 'Создаем объект для чтения результатов запроса
Do While reader.Read 'Читаем результат
'Добавляем записи в наш список
Table.Add(New TestNull(reader.GetInt32(0), reader.GetString(1), reader.GetDateTime(2), GetValue(reader(3))))
Loop
con.Close() 'Закрываем соединение
End Using
'Цикл вывода данных на экран
For Each Item As TestNull In Table
Console.WriteLine("ID={0},Name={1},DateBegin={2},DateEnd={3}", Item.id, Item.Name, Item.DateBegin, GetValue(Item.DateEnd))
Next
Console.ReadKey()
End Sub
''' <summary>
''' Функция для проверки значение на DBNull
''' </summary>
''' <remarks>Данная функция создана из-за того, что IIF в VB.NET вычисляет все значения ей передаваемые, в отличие от С-ой ?:</remarks>
Private Shared Function GetValue(ByRef obj As Object) As Nullable(Of DateTime)
If IsDBNull(obj) Then
Return Nothing
Else
Return CType(obj, Nullable(Of DateTime))
End If
End Function
''' <summary>
''' Так же из-за корявой работы функции IIF приходится делать отдельную функцию обработки значения.
''' </summary>
Private Shared Function GetValue(ByRef obj As Nullable(Of DateTime)) As String
If obj.HasValue Then
Return obj.Value.ToString
Else
Return "NULL"
End If
End Function
End Class
End Namespace
Что бы полнее рассмотреть вопрос работы со структурой Nullable, мне хотелось бы рассмотреть еще несколько примеров:
Использование GetValueOrDefault:
C#
int? i=null;//Определяем переменную i как Nullable<int> со значение NULL
Console.WriteLine(i ?? 444); //Результат 444
Console.WriteLine(i.GetValueOrDefault()); //Результат 0 - значение int по умолчанию
i = 44; //Записываем значение
Console.WriteLine(i.GetValueOrDefault(3)); //Результат 44
Console.WriteLine(i); //Результат 44
VB.NET
Dim i As Nullable(Of Integer) = Nothing 'Определяем переменную i как Nullable(Of Integer) со значение Nothing
Console.WriteLine(i.GetValueOrDefault(444)) 'Результат 444
Console.WriteLine(i.GetValueOrDefault) 'Результат 0 - значение int по умолчанию
i = 44 'Записываем значение
Console.WriteLine(i.GetValueOrDefault(3)) 'Результат 44
Console.WriteLine(i) 'Результат 44
Использование Compare:
C#
int? a = null;//Определяем переменную a как Nullable<int> со значение NULL
int? b = null;//Определяем переменную b как Nullable<int> со значение NULL
Console.WriteLine(Nullable.Compare(a, b)); //Результат 0
a = 1;b = null;
Console.WriteLine(Nullable.Compare(a, b)); //Результат 1
a = null;b = 1;
Console.WriteLine(Nullable.Compare(a, b)); //Результат -1
a = 0;b = 1;
Console.WriteLine(Nullable.Compare(a, b)); //Результат -1
a = 1;b = 0;
Console.WriteLine(Nullable.Compare(a, b)); //Результат 1
VB.NET
Dim a As Nullable(Of Integer) = Nothing 'Определяем переменную a как Nullable<int> со значение Nothing
Dim b As Nullable(Of Integer) = Nothing 'Определяем переменную b как Nullable<int> со значение Nothing
Console.WriteLine(Nullable.Compare(a, b)) 'Результат 0
a = 1 : b = Nothing
Console.WriteLine(Nullable.Compare(a, b)) 'Результат 1
a = Nothing : b = 1
Console.WriteLine(Nullable.Compare(a, b)) 'Результат -1
a = 0 : b = 1
Console.WriteLine(Nullable.Compare(a, b)) 'Результат -1
a = 1 : b = 0
Console.WriteLine(Nullable.Compare(a, b)) 'Результат 1
P.S.
Изучив основы использования класса и структуры Nullable, видно, что данную технологию широко можно использовать в языке C#, ведь даже компилятор C# позволяет использовать сокращенный синтаксис:
int?, в место Nullable<int>
item ?? 1, в место item.GetValueOrDefault(1)
А вот ее использование в языке Visual Basic .NET затруднительно, так как придется использовать полное обращение к структуре Nullable(of Integer), а так же основную проблемы вызывает функция IIF, которая, как и в VB6 с начала выполняет все операции, которые ей передали, а только лишь затем выполняет проверку.
C...R...a...S...H
16 July 2006 22:03 Комментарии (1)
|