Zpracování hodnot null
Hodnota null v relační databázi se používá, pokud je hodnota ve sloupci neznámá nebo chybí. Hodnota null není prázdný řetězec (pro datové typy character ani datetime) ani nulová hodnota (pro číselné datové typy). Specifikace ANSI SQL-92 uvádí, že hodnota null musí být stejná pro všechny datové typy, aby se všechny hodnoty null zpracovávaly konzistentně. Obor System.Data.SqlTypes názvů poskytuje sémantiku null implementací INullable rozhraní. Každý z datových typů má System.Data.SqlTypes svou vlastní IsNull
vlastnost a Null
hodnotu, která se dá přiřadit k instanci tohoto datového typu.
Poznámka:
Rozhraní .NET Framework verze 2.0 zavedlo podporu pro typy hodnot s možnou hodnotou null, které programátorům umožňují rozšířit typ hodnoty tak, aby představovaly všechny hodnoty základního typu. Tyto typy hodnot CLR s možnou Nullable hodnotou null představují instanci struktury. Tato funkce je užitečná zejména v případě, že jsou typy hodnot v rámečku a rozbalené, což poskytuje vylepšenou kompatibilitu s typy objektů. Typy hodnot CLR s možnou null
hodnotou null nejsou určeny pro ukládání hodnot null databáze, protože hodnota NULL ANSI SQL se nechová stejně jako odkaz (nebo Nothing
v jazyce Visual Basic). Pro práci s databázovými hodnotami ANSI SQL s hodnotou null použijte System.Data.SqlTypes hodnoty null místo Nullable. Další informace o práci s typy hodnot CLR s možnou hodnotou null v jazyce Visual Basic naleznete v tématu Typy hodnot s možnou hodnotou Null a pro C# viz Typy hodnot s možnou hodnotou Null.
Logika null a tříhodnotová
Povolení hodnot null v definicích sloupců zavádí do vaší aplikace tříhodnotovou logiku. Porovnání se může vyhodnotit na jednu ze tří podmínek:
True
False
Neznámý
Vzhledem k tomu, že hodnota null je považována za neznámou, nejsou dvě hodnoty null ve srovnání s ostatními považovány za stejné. Ve výrazech používajících aritmetické operátory, pokud některý z operandů má hodnotu null, je výsledek také null.
Hodnoty Null a SqlBoolean
Porovnání mezi všemi System.Data.SqlTypes vrátí hodnotu SqlBoolean. Funkce IsNull
pro každou SqlType
vrací hodnotu SqlBoolean a lze ji použít ke kontrole hodnot null. Následující tabulky pravdy ukazují, jak operátory AND, OR a NOT fungují v přítomnosti hodnoty null. (T=true, F=false a U=unknown nebo null.)
Vysvětlení možnosti ANSI_NULLS
System.Data.SqlTypes poskytuje stejnou sémantiku jako při nastavení možnosti ANSI_NULLS na SQL Serveru. Všechny aritmetické operátory (+, -, *, /, %), bitové operátory (~, &, |) a většina funkcí vrátí hodnotu null, pokud některý z operandů nebo argumentů má hodnotu null, s výjimkou vlastnosti IsNull
.
Standard ANSI SQL-92 nepodporuje columnName = NULL v klauzuli WHERE. V SQL Serveru řídí možnost ANSI_NULLS výchozí hodnotu null v databázi i vyhodnocení porovnání s hodnotami null. Pokud je ANSI_NULLS zapnutá (výchozí), musí být při testování hodnot null použit operátor IS NULL ve výrazech. Například následující porovnání vždy přináší neznámé, pokud je ANSI_NULLS zapnuto:
colname > NULL
Porovnání s proměnnou obsahující hodnotu null také přináší neznámé hodnoty:
colname > @MyVariable
K otestování hodnoty null použijte predikát IS NULL nebo IS NOT NULL. To může do klauzule WHERE přidat složitost. Například sloupec TerritoryID v tabulce AdventureWorks Customer umožňuje hodnoty null. Pokud má příkaz SELECT kromě jiných testovat hodnoty null, musí obsahovat predikát IS NULL:
SELECT CustomerID, AccountNumber, TerritoryID
FROM AdventureWorks.Sales.Customer
WHERE TerritoryID IN (1, 2, 3)
OR TerritoryID IS NULL
Pokud nastavíte ANSI_NULLS v SQL Serveru, můžete vytvořit výrazy, které používají operátor rovnosti k porovnání s hodnotou null. Nemůžete ale zabránit tomu, aby různá připojení nastavily možnosti null pro toto připojení. Použití hodnoty IS NULL k testování hodnot null vždy funguje bez ohledu na nastavení ANSI_NULLS připojení.
Nastavení ANSI_NULLS vypnuto není podporováno v rozhraní DataSet
, které vždy dodržuje standard ANSI SQL-92 pro zpracování hodnot null v System.Data.SqlTypes.
Přiřazení hodnot Null
Hodnoty null jsou speciální a jejich sémantika úložiště a přiřazení se liší v různých systémech typů a úložných systémech. A Dataset
je navržená tak, aby se používala s různými typy a úložnými systémy.
Tato část popisuje sémantiku null pro přiřazování hodnot null do DataColumn různých DataRow systémů typů.
DBNull.Value
Toto přiřazení je platné pro DataColumn
libovolný typ. Pokud se typ implementuje INullable
, DBNull.Value
je přetěžován na odpovídající hodnotu null silného typu.
SqlType.Null
Všechny System.Data.SqlTypes datové typy implementují INullable
. Pokud lze hodnotu null silného typu převést na datový typ sloupce pomocí implicitních operátorů přetypování, přiřazení by mělo projít. V opačném případě je vyvolán neplatná výjimka přetypování.
null
Pokud je hodnota null pro daný DataColumn
datový typ právní hodnota, převede se do příslušného DbNull.Value
nebo Null
přidruženého INullable
typu (SqlType.Null
).
derivedUdt.Null
U sloupců UDT se hodnoty null vždy ukládají na základě typu přidruženého k sadě DataColumn
. Vezměte v úvahu případ UDT přidruženého k DataColumn
tomu, který se neimplementuje INullable
, zatímco jeho podtřída dělá. V tomto případě, pokud je přiřazena hodnota null silného typu přidružená k odvozené třídě, je uložena jako nezadaná DbNull.Value
, protože úložiště null je vždy konzistentní s datovým typem DataColumn.
Poznámka:
Struktura Nullable<T>
není Nullable v současné době podporována v systému DataSet
.
Výchozí hodnota pro libovolnou System.Data.SqlTypes instanci je null.
System.Data.SqlTypes Hodnoty Null jsou specifické pro typ a nelze je reprezentovat jednou hodnotou, například DbNull
. IsNull
Pomocí vlastnosti zkontrolujte hodnoty null.
Hodnoty Null lze přiřadit k objektu DataColumn , jak je znázorněno v následujícím příkladu kódu. Proměnné můžete přímo přiřadit hodnoty SqlTypes
null bez aktivace výjimky.
Příklad
Následující příklad kódu vytvoří se DataTable dvěma sloupci definovanými jako SqlInt32 a SqlString. Kód přidá jeden řádek známých hodnot, jeden řádek hodnot null a pak iteruje DataTable, přiřadí hodnoty proměnným a zobrazí výstup v okně konzoly.
static void WorkWithSqlNulls()
{
DataTable table = new();
// Specify the SqlType for each column.
DataColumn idColumn =
table.Columns.Add("ID", typeof(SqlInt32));
DataColumn descColumn =
table.Columns.Add("Description", typeof(SqlString));
// Add some data.
DataRow nRow = table.NewRow();
nRow["ID"] = 123;
nRow["Description"] = "Side Mirror";
table.Rows.Add(nRow);
// Add null values.
nRow = table.NewRow();
nRow["ID"] = SqlInt32.Null;
nRow["Description"] = SqlString.Null;
table.Rows.Add(nRow);
// Initialize variables to use when
// extracting the data.
SqlBoolean isColumnNull = false;
SqlInt32 idValue = SqlInt32.Zero;
SqlString descriptionValue = SqlString.Null;
// Iterate through the DataTable and display the values.
foreach (DataRow row in table.Rows)
{
// Assign values to variables. Note that you
// do not have to test for null values.
idValue = (SqlInt32)row["ID"];
descriptionValue = (SqlString)row["Description"];
// Test for null value in ID column.
isColumnNull = idValue.IsNull;
// Display variable values in console window.
Console.Write("isColumnNull={0}, ID={1}, Description={2}",
isColumnNull, idValue, descriptionValue);
Console.WriteLine();
}
Private Sub WorkWithSqlNulls()
Dim table As New DataTable()
' Specify the SqlType for each column.
Dim idColumn As DataColumn = _
table.Columns.Add("ID", GetType(SqlInt32))
Dim descColumn As DataColumn = _
table.Columns.Add("Description", GetType(SqlString))
' Add some data.
Dim row As DataRow = table.NewRow()
row("ID") = 123
row("Description") = "Side Mirror"
table.Rows.Add(row)
' Add null values.
row = table.NewRow()
row("ID") = SqlInt32.Null
row("Description") = SqlString.Null
table.Rows.Add(row)
' Initialize variables to use when
' extracting the data.
Dim isColumnNull As SqlBoolean = False
Dim idValue As SqlInt32 = SqlInt32.Zero
Dim descriptionValue As SqlString = SqlString.Null
' Iterate through the DataTable and display the values.
For Each row In table.Rows
' Assign values to variables. Note that you
' do not have to test for null values.
idValue = CType(row("ID"), SqlInt32)
descriptionValue = CType(row("Description"), SqlString)
' Test for null value with ID column
isColumnNull = idValue.IsNull
' Display variable values in console window.
Console.Write("isColumnNull={0}, ID={1}, Description={2}", _
isColumnNull, idValue, descriptionValue)
Console.WriteLine()
Next row
End Sub
Tento příklad zobrazí následující výsledky:
isColumnNull=False, ID=123, Description=Side Mirror
isColumnNull=True, ID=Null, Description=Null
Přiřazení více sloupců (řádků)
DataTable.Add
, DataTable.LoadDataRow
nebo jiná rozhraní API, která přijímají ItemArray mapování na řádek, mapuje hodnotu null na výchozí hodnotu DataColumn. Pokud objekt v poli obsahuje DbNull.Value
nebo jeho protějšek silného typu, použijí se stejná pravidla, jak je popsáno výše.
Kromě toho platí následující pravidla pro instanci DataRow.["columnName"]
přiřazení null:
Výchozí hodnota je
DbNull.Value
pro všechny kromě sloupců null silného typu, kde se jedná o odpovídající hodnotu null silného typu.Hodnoty Null se při serializaci nikdy nezapisují do souborů XML (jako v xsi:nil).
Všechny hodnoty, které nejsou null, včetně výchozích hodnot, se při serializaci do XML vždy zapisují. Je to na rozdíl od sémantiky XSD/XML, kde je explicitní hodnota null (xsi:nil) a výchozí hodnota je implicitní (pokud není k dispozici ve formátu XML, může ji validační analyzátor získat z přidruženého schématu XSD). Opak platí pro
DataTable
: hodnota null je implicitní a výchozí hodnota je explicitní.Všechny chybějící hodnoty sloupců pro řádky přečtené ze vstupu XML mají přiřazenou hodnotu NULL. Řádkům vytvořeným pomocí NewRow nebo podobným metodám se přiřadí výchozí hodnota DataColumn.
Metoda IsNull vrátí
true
pro oběDbNull.Value
aINullable.Null
.
Porovnání hodnot Null s typy SqlTypes a CLR
Při porovnávání hodnot null je důležité pochopit rozdíl mezi tím, jak Equals
metoda vyhodnocuje hodnoty System.Data.SqlTypes null ve srovnání se způsobem, jakým funguje s typy CLR. System.Data.SqlTypesEquals
Všechny metody používají k vyhodnocení hodnot null sémantiku databáze: pokud je hodnota null nebo obě hodnoty null, porovnání má hodnotu null. Na druhou stranu použití CLR Equals
metoda na dvou System.Data.SqlTypes bude mít hodnotu true, pokud oba mají hodnotu null. To odráží rozdíl mezi použitím metody instance, jako je clr String.Equals
metoda, a pomocí statické/sdílené metody, SqlString.Equals
.
Následující příklad ukazuje rozdíl ve výsledcích mezi metodou SqlString.Equals
a metodou String.Equals
při každém předání dvojice hodnot null a pak pár prázdných řetězců.
static void CompareNulls()
{
// Create two new null strings.
SqlString a = new();
SqlString b = new();
// Compare nulls using static/shared SqlString.Equals.
Console.WriteLine("SqlString.Equals shared/static method:");
Console.WriteLine(" Two nulls={0}", SqlStringEquals(a, b));
// Compare nulls using instance method String.Equals.
Console.WriteLine();
Console.WriteLine("String.Equals instance method:");
Console.WriteLine(" Two nulls={0}", StringEquals(a, b));
// Make them empty strings.
a = "";
b = "";
// When comparing two empty strings (""), both the shared/static and
// the instance Equals methods evaluate to true.
Console.WriteLine();
Console.WriteLine("SqlString.Equals shared/static method:");
Console.WriteLine(" Two empty strings={0}", SqlStringEquals(a, b));
Console.WriteLine();
Console.WriteLine("String.Equals instance method:");
Console.WriteLine(" Two empty strings={0}", StringEquals(a, b));
}
static string SqlStringEquals(SqlString string1, SqlString string2)
{
// SqlString.Equals uses database semantics for evaluating nulls.
var returnValue = SqlString.Equals(string1, string2).ToString();
return returnValue;
}
static string StringEquals(SqlString string1, SqlString string2)
{
// String.Equals uses CLR type semantics for evaluating nulls.
var returnValue = string1.Equals(string2).ToString();
return returnValue;
}
}
Private Sub CompareNulls()
' Create two new null strings.
Dim a As New SqlString
Dim b As New SqlString
' Compare nulls using static/shared SqlString.Equals.
Console.WriteLine("SqlString.Equals shared/static method:")
Console.WriteLine(" Two nulls={0}", SqlStringEquals(a, b))
' Compare nulls using instance method String.Equals.
Console.WriteLine()
Console.WriteLine("String.Equals instance method:")
Console.WriteLine(" Two nulls={0}", StringEquals(a, b))
' Make them empty strings.
a = ""
b = ""
' When comparing two empty strings (""), both the shared/static and
' the instance Equals methods evaluate to true.
Console.WriteLine()
Console.WriteLine("SqlString.Equals shared/static method:")
Console.WriteLine(" Two empty strings={0}", SqlStringEquals(a, b))
Console.WriteLine()
Console.WriteLine("String.Equals instance method:")
Console.WriteLine(" Two empty strings={0}", StringEquals(a, b))
End Sub
Private Function SqlStringEquals(ByVal string1 As SqlString, _
ByVal string2 As SqlString) As String
' SqlString.Equals uses database semantics for evaluating nulls.
Dim returnValue As String = SqlString.Equals(string1, string2).ToString()
Return returnValue
End Function
Private Function StringEquals(ByVal string1 As SqlString, _
ByVal string2 As SqlString) As String
' String.Equals uses CLR type semantics for evaluating nulls.
Dim returnValue As String = string1.Equals(string2).ToString()
Return returnValue
End Function
Kód vytvoří následující výstup:
SqlString.Equals shared/static method:
Two nulls=Null
String.Equals instance method:
Two nulls=True
SqlString.Equals shared/static method:
Two empty strings=True
String.Equals instance method:
Two empty strings=True