Delen via


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.)

Truth Table

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.LoadDataRowof 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:

  1. De standaardwaarde is DbNull.Value voor iedereen, met uitzondering van de sterk getypte null-kolommen, waarbij deze de juiste sterk getypte null-waarde is.

  2. Null-waarden worden nooit weggeschreven tijdens serialisatie naar XML-bestanden (zoals in 'xsi:nil').

  3. 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.

  4. 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.

  5. De IsNull methode retourneert true voor zowel DbNull.Value als INullable.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

Zie ook