Null-waarden verwerken
Een null-waarde in een relationele database wordt gebruikt wanneer de waarde in een kolom onbekend of ontbreekt. Een null is geen lege tekenreeks (voor gegevenstypen teken of datum/tijd) of een nulwaarde (voor numerieke gegevenstypen). De ANSI SQL-92-specificatie geeft aan dat een null hetzelfde moet zijn voor alle gegevenstypen, zodat alle null-waarden consistent worden verwerkt. De System.Data.SqlTypes naamruimte biedt null-semantiek door de INullable interface te implementeren. Elk van de gegevenstypen in System.Data.SqlTypes heeft een eigen IsNull
eigenschap en een Null
waarde die kan worden toegewezen aan een exemplaar van dat gegevenstype.
Notitie
In .NET Framework versie 2.0 is ondersteuning geïntroduceerd voor typen null-waarden, waarmee programmeurs een waardetype kunnen uitbreiden om alle waarden van het onderliggende type weer te geven. Deze clr nullable waardetypen vertegenwoordigen een exemplaar van de Nullable structuur. Deze mogelijkheid is vooral handig wanneer waardetypen in een vak worden geplaatst en niet in het postvak worden geplaatst, waardoor de compatibiliteit met objecttypen wordt verbeterd. CLR nullable value types zijn niet bedoeld voor de opslag van database nulls omdat een ANSI SQL Null zich niet op dezelfde manier gedraagt als een null
verwijzing (of Nothing
in Visual Basic). Gebruik null-waarden voor database ANSI SQL in plaats Nullablevan null-waarden System.Data.SqlTypes voor databases. Zie Nullable Value Types in Visual Basic voor meer informatie over het werken met clr-waarden en voor C# null-waardetypen.
Null-waarden en logica met drie waarden
Het toestaan van null-waarden in kolomdefinities introduceert drie-waardelogica in uw toepassing. Een vergelijking kan resulteren in een van drie voorwaarden:
Waar
Onwaar
Onbekend
Omdat null als onbekend wordt beschouwd, worden twee null-waarden vergeleken met elkaar niet als gelijk beschouwd. Als een van de operanden null is in expressies die rekenkundige operatoren gebruiken, is het resultaat ook null.
Nulls en SqlBoolean
Vergelijking tussen elke System.Data.SqlTypes waarde retourneert een SqlBoolean. De IsNull
functie voor elke SqlType
functie retourneert een SqlBoolean en kan worden gebruikt om te controleren op null-waarden. In de volgende waarheidstabellen ziet u hoe de operators AND, OR en NOT werken in aanwezigheid van een null-waarde. (T=true, F=false, and U=unknown, or null.)
Informatie over de ANSI_NULLS-optie
System.Data.SqlTypes biedt dezelfde semantiek als wanneer de optie ANSI_NULLS is ingesteld in SQL Server. Alle rekenkundige operatoren (+, -, *, /, %), bitsgewijze operatoren (~, &, |) en de meeste functies retourneren null als een van de operanden of argumenten null is, met uitzondering van de eigenschap IsNull
.
De ANSI SQL-92-standaard biedt geen ondersteuning voor columnName = NULL in een WHERE-component. In SQL Server bepaalt de optie ANSI_NULLS zowel de standaard null-waarde in de database als de evaluatie van vergelijkingen met null-waarden. Als ANSI_NULLS is ingeschakeld (de standaardinstelling), moet de IS NULL-operator worden gebruikt in expressies bij het testen van null-waarden. De volgende vergelijking levert bijvoorbeeld altijd onbekend op wanneer ANSI_NULLS is ingeschakeld:
colname > NULL
Vergelijking met een variabele die een null-waarde bevat, resulteert ook in onbekend:
colname > @MyVariable
Gebruik het predicaat IS NULL of IS NOT NULL om te testen op een null-waarde. Dit kan complexiteit toevoegen aan de WHERE-component. De kolom TerritoryID in de tabel AdventureWorks Customer staat bijvoorbeeld null-waarden toe. Als een SELECT-instructie is om naast andere null-waarden te testen, moet deze een IS NULL-predicaat bevatten:
SELECT CustomerID, AccountNumber, TerritoryID
FROM AdventureWorks.Sales.Customer
WHERE TerritoryID IN (1, 2, 3)
OR TerritoryID IS NULL
Als u ANSI_NULLS uitschakelt in SQL Server, kunt u expressies maken die de gelijkheidsoperator gebruiken om te vergelijken met null. U kunt echter niet voorkomen dat verschillende verbindingen null-opties voor die verbinding instellen. Het gebruik van IS NULL om te testen op null-waarden werkt altijd, ongeacht de ANSI_NULLS instellingen voor een verbinding.
Het instellen van ANSI_NULLS uit wordt niet ondersteund in een DataSet
, dat altijd de ANSI SQL-92-standaard volgt voor het verwerken van null-waarden in System.Data.SqlTypes.
Null-waarden toewijzen
Null-waarden zijn speciaal en de semantiek voor opslag en toewijzing verschillen in verschillende typesystemen en opslagsystemen. Een Dataset
is ontworpen voor gebruik met verschillende typen en opslagsystemen.
In deze sectie worden de null-semantiek beschreven voor het toewijzen van null-waarden aan een DataColumn in een in een DataRow van de verschillende typesystemen.
DBNull.Value
Deze toewijzing is geldig voor een DataColumn
van het type. Als het type wordt geïmplementeerd INullable
, DBNull.Value
wordt deze in de juiste sterk getypte Null-waarde afgedwongen.
SqlType.Null
Alle System.Data.SqlTypes gegevenstypen worden geïmplementeerd INullable
. Als de sterk getypte null-waarde kan worden geconverteerd naar het gegevenstype van de kolom met behulp van impliciete cast-operators, moet de toewijzing worden doorlopen. Anders wordt er een ongeldige cast-uitzondering gegenereerd.
null
Als 'null' een juridische waarde is voor het opgegeven DataColumn
gegevenstype, wordt deze in de juiste DbNull.Value
of Null
gekoppeld aan het INullable
type (SqlType.Null
)
derivedUdt.Null
Voor UDT-kolommen worden null-waarden altijd opgeslagen op basis van het type dat is gekoppeld aan de DataColumn
. Houd rekening met het geval van een UDT dat is gekoppeld aan een DataColumn
UDT die niet wordt geïmplementeerd INullable
terwijl de subklasse dat wel doet. Als in dit geval een sterk getypte null-waarde is toegewezen die is gekoppeld aan de afgeleide klasse, wordt deze opgeslagen als een niet-getypt DbNull.Value
, omdat null-opslag altijd consistent is met het gegevenstype van DataColumn.
Notitie
De Nullable<T>
of Nullable structuur wordt momenteel niet ondersteund in de DataSet
.
De standaardwaarde voor een System.Data.SqlTypes exemplaar is null.
Null-waarden in System.Data.SqlTypes zijn typespecifiek en kunnen niet worden vertegenwoordigd door één waarde, zoals DbNull
. Gebruik de IsNull
eigenschap om te controleren op null-waarden.
Null-waarden kunnen worden toegewezen aan een DataColumn waarde die wordt weergegeven in het volgende codevoorbeeld. U kunt null-waarden rechtstreeks toewijzen aan SqlTypes
variabelen zonder een uitzondering te activeren.
Opmerking
In het volgende codevoorbeeld wordt een DataTable met twee kolommen gemaakt die zijn gedefinieerd als SqlInt32 en SqlString. De code voegt één rij met bekende waarden toe, één rij met null-waarden en doorloopt vervolgens de DataTablewaarden, wijst de waarden toe aan variabelen en geeft de uitvoer weer in het consolevenster.
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
In dit voorbeeld worden de volgende resultaten weergegeven:
isColumnNull=False, ID=123, Description=Side Mirror
isColumnNull=True, ID=Null, Description=Null
Toewijzing van meerdere kolommen (rij)
DataTable.Add
, DataTable.LoadDataRow
of andere API's die een ItemArray api accepteren die wordt toegewezen aan een rij, 'null' toewijzen aan de standaardwaarde van DataColumn. Als een object in de matrix een sterk getypte tegenhanger bevat DbNull.Value
, worden dezelfde regels toegepast als hierboven beschreven.
Daarnaast zijn de volgende regels van toepassing op een exemplaar van DataRow.["columnName"]
null-toewijzingen:
De standaardwaarde is
DbNull.Value
voor iedereen, met uitzondering van de sterk getypte null-kolommen, waarbij deze de juiste sterk getypte null-waarde is.Null-waarden worden nooit weggeschreven tijdens serialisatie naar XML-bestanden (zoals in 'xsi:nil').
Alle niet-null-waarden, inclusief standaardwaarden, worden altijd weggeschreven tijdens het serialiseren naar XML. Dit is in tegenstelling tot XSD/XML-semantiek waarbij een null-waarde (xsi:nil) expliciet is en de standaardwaarde impliciet is (als deze niet aanwezig is in XML, kan een validerende parser deze ophalen uit een gekoppeld XSD-schema). Het tegenovergestelde geldt voor een
DataTable
: een null-waarde is impliciet en de standaardwaarde is expliciet.Alle ontbrekende kolomwaarden voor rijen die worden gelezen uit XML-invoer, worden NULL toegewezen. Rijen die zijn gemaakt met behulp van NewRow of vergelijkbare methoden, krijgen de standaardwaarde van DataColumn toegewezen.
De IsNull methode retourneert
true
voor zowelDbNull.Value
alsINullable.Null
.
Null-waarden vergelijken met SqlTypes en CLR-typen
Bij het vergelijken van null-waarden is het belangrijk om inzicht te hebben in het verschil tussen de manier waarop de Equals
methode null-waarden System.Data.SqlTypes evalueert in vergelijking met de manier waarop de methode werkt met CLR-typen. Alle methoden maken gebruik van System.Data.SqlTypesEquals
database-semantiek voor het evalueren van null-waarden: als een van beide waarden null is, levert de vergelijking null op. Aan de andere kant levert het gebruik van de CLR-methode Equals
op twee System.Data.SqlTypes waar als beide null zijn. Dit weerspiegelt het verschil tussen het gebruik van een instantiemethode zoals de CLR-methode String.Equals
en het gebruik van de statische/gedeelde methode. SqlString.Equals
In het volgende voorbeeld ziet u het verschil in resultaten tussen de SqlString.Equals
methode en de String.Equals
methode wanneer elk wordt doorgegeven aan een paar null-waarden en vervolgens een paar lege tekenreeksen.
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
De code produceert de volgende uitvoer:
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