Domanda

In .NET v'è il riferimento null, che viene utilizzato in tutto il mondo per indicare che un riferimento a un oggetto è vuoto, e poi c'è il DBNull, che viene utilizzato da driver di database (e pochi altri) per indicare ... più o meno la stessa cosa. Naturalmente, questo crea un sacco di confusione e di conversione routine devono essere sfornato, ecc.

Allora perché l'autore originale NET decidono di fare questo? Per me non ha senso. La loro documentazione non ha senso neanche:

La classe DBNull rappresenta un valore inesistente. In un database, per esempio, una colonna in una riga di una tabella potrebbe non contenere alcun dato. Cioè, la colonna viene considerato non esistere invece di limitarsi a non avere un valore. Un oggetto DBNull rappresenta la colonna inesistente. Inoltre, interoperabilità COM utilizza la classe DBNull di distinguere tra una variante VT_NULL, che indica un valore inesistente, e una variante VT_EMPTY, che indica un valore specificato.

Da questa merda di una "colonna non esistente"? Esiste una colonna, semplicemente non ha un valore per la riga particolare. Se non esistesse, mi piacerebbe avere un eccezione durante il tentativo di accedere alla cella specifica, non un DBNull! Posso capire la necessità di distinguere tra VT_NULL e VT_EMPTY, ma allora perché non fare una classe COMEmpty invece? Questa sarebbe una forma più ordinata molto in tutto il framework .NET.

mi sto perdendo qualcosa? Qualcuno può far luce perché è stato inventato DBNull e quali problemi si aiuta a risolvere?

È stato utile?

Soluzione

Il punto è che in certe situazioni c'è una differenza tra un valore del database essendo nullo e un Null NET.

Ad esempio. Se si utilizza ExecuteScalar (che restituisce la prima colonna della prima riga del set di risultati) e si ottiene un back nulla che significa che lo SQL eseguito non ha restituito alcun valore. Se si ottiene DBNull indietro significa un valore è stato restituito dal SQL ed era NULL. È necessario essere in grado di capire la differenza.

Altri suggerimenti

ho intenzione di essere in disaccordo con la tendenza qui. Andrò a verbale:

Non sono d'accordo che DBNull serve uno scopo utile; aggiunge inutile confusione, contribuendo praticamente alcun valore.

L'argomento viene spesso avanzata che null è un riferimento valido, e che DBNull è un modello oggetto nullo; non è vero . Ad esempio:

int? x = null;

questo non è un "riferimento non valido"; è un valore null. Infatti mezzi null quello che vuoi che significhi, e francamente non ho assolutamente alcun problema a lavorare con i valori che possono essere null (anzi, anche in SQL dobbiamo correttamente il lavoro con null - non cambia nulla qui). Allo stesso modo, il "modello oggetto nullo" ha senso solo se in realtà si sta trattando come un oggetto in termini OOP, ma se abbiamo un valore che può essere "il nostro valore, o un DBNull" allora deve essere object, in modo che possiamo 't essere facendo qualcosa di utile con esso.

Ci sono così tante cose cattive con DBNull:

  • ti costringe a lavorare con object, dal momento che solo object può contenere DBNull o un altro valore
  • non esiste una vera differenza tra "potrebbe essere un valore o DBNull" vs "potrebbe essere un valore o null"
  • l'argomento che deriva da 1.1 (pre-nullable tipi) è insignificante; potremmo usare null perfettamente in 1.1
  • la maggior parte delle API hanno "è nullo?" metodi, per esempio DBDataReader.IsDBNull o DataRow.IsNull - nessuno dei quali effettivamente richiedono DBNull di esistere in termini di API
  • DBNull non in termini di null-coalescenza; value ?? defaultValue non funziona se il valore è DBNull
  • DBNull.Value non può essere utilizzato nei parametri opzionali, in quanto non è una costante
  • la semantica di esecuzione di DBNull sono identiche alla semantica null; in particolare, in realtà è uguale a DBNull DBNull - in modo che non fare il lavoro di rappresentare la semantica SQL
  • spesso costringe i valori tipo valore per essere inscatolati in quanto lo consegna usi object
  • se avete bisogno di prova per DBNull, si potrebbe anche hanno testato solo per null
  • provoca enormi problemi per cose come parametri-comando, con un comportamento molto stupido che se un parametro ha un valore null non è inviato ... beh, ecco un'idea: se non si desidera un inviato parametro - non aggiungere alla collezione parametri
  • ogni ORM mi viene in mente funziona perfettamente senza qualsiasi necessità o l'uso di DBNull, se non come un fastidio in più quando si parla al codice ADO.NET

L'unica anche da remoto argomento convincente Sono mai visto per giustificare la esistenza di un tale valore è in DataTable, quando passa in valori per creare una nuova riga; un mezzo null "all'utente predefinita", un DBNull è esplicitamente null - francamente questa API potrebbe avere un trattamento specifico per questo caso - un DataRow.DefaultValue immaginaria per esempio sarebbe molto meglio che introdurre un DBNull.Value che infetta vaste aree di codice per nessun ragione.

Allo stesso modo, lo scenario è ExecuteScalar ... debole come non mai; se si sta eseguendo un metodo scalare, si aspettarsi un risultato. Nello scenario in cui non ci sono righe, di ritorno null non sembra troppo terribile. Se è assolutamente necessario di disambiguare tra "nessuna riga" e "una sola nulla restituito", c'è l'API lettore.

Questa nave è salpata da molto tempo, ed è di gran lunga troppo tardi per risolvere il problema. Ma! Si prega di fare non pensare che tutti sono d'accordo chequesta è una cosa "ovvia". Molti sviluppatori fanno non vedere il valore in questo strano rughe sul BCL.

Io in realtà chiedo se tutto questo deriva da due cose:

  • dover usare la parola Nothing invece di qualcosa che coinvolge "null" in VB
  • essere in grado di noi la sintassi if(value is DBNull) che "sembra proprio SQL", piuttosto che il if(value==null) oh-così-ingannevole

Sommario:

Avere 3 opzioni (null, DBNull, o un valore effettivo) è utile solo se v'è un vero e proprio esempio in cui è necessario disambiguare tra i 3 casi differenti. Devo ancora vedere un'occasione in cui ho bisogno di rappresentare due diversi stati "null", in modo da DBNull è interamente ridondante, dato che null già esiste e ha molto migliore supporto per la lingua e la fase di esecuzione.

DbNull rappresenta una scatola senza contenuti; null indica l'inesistenza della scatola.

È possibile utilizzare DBNull per i dati mancanti. Null nei mezzi linguaggio .NET che non v'è alcun puntatore di un oggetto / variabile.

DBNull dati mancanti: http://msdn.microsoft. com / it-it / library / system.dbnull.value.aspx

Gli effetti dei dati mancanti sulle statistiche:

http://en.wikipedia.org/wiki/Missing_values ??

Ci sono alcune differenze tra un valore nullo CLR e DBNull. In primo luogo, null nel database relazionali ha diversi "uguale" semantica: null non è uguale a zero. CLR nulla è uguale a zero.

Ma ho il sospetto la ragione principale è quello di fare con il parametro modo in cui i valori di default di lavoro in SQL Server e l'implementazione del provider.

Per vedere la differenza, creare una procedura con un parametro che ha un valore di default:

CREATE PROC [Echo] @s varchar(MAX) = 'hello'
AS
    SELECT @s [Echo]

Codice DAL ben strutturato dovrebbe separare la creazione dei comandi da utilizzare (per abilitare utilizzando lo stesso comando più volte, ad esempio per invocare una stored procedure molte volte in modo efficiente). Scrivere un metodo che restituisce uno SqlCommand che rappresenta la procedura di cui sopra:

SqlCommand GetEchoProc()
{
    var cmd = new SqlCommand("Echo");
    cmd.Parameters.Add("@s", SqlDbType.VarChar);
    return cmd;
}

Se ora richiamare il comando senza impostare il parametro @S, o impostarne il valore (CLR) null, verrà utilizzato il valore di default 'ciao'. Se d'altra parte si imposta il valore del parametro per DBNull.Value, userà quello e eco DBNull.Value.

Dal momento che ci sono due risultati diversi utilizzando nulla CLR o null database come valore di parametro, non è possibile rappresentare entrambi i casi con uno solo di essi. Se CLR nulla è stato quello di essere l'unico, che avrebbe dovuto lavorare nel modo DBNull.Value fa oggi. Un modo per indicare al provider "Voglio utilizzare il valore predefinito" potrebbe allora essere quello di non dichiarare il parametro a tutti (un parametro con un valore di default, naturalmente, ha senso per descrivere come un "parametro opzionale"), ma in un scenario in cui l'oggetto di comando viene memorizzato nella cache e riutilizzato questo fa portare a rimuovere e ri-aggiungendo il parametro.

Non sono sicuro se penso DBNull era una buona idea o no, ma un sacco di persone non sono consapevoli delle cose che ho detto qui, così ho pensato che vale la pena menzionare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top