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

Truth Table

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

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

  2. Hodnoty Null se při serializaci nikdy nezapisují do souborů XML (jako v xsi:nil).

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

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

  5. Metoda IsNull vrátí true pro obě DbNull.Value a INullable.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

Viz také