375 Stimmen

SQL Data Reader - Behandlung von Null-Spaltenwerten

Ich verwende einen SQLdatareader, um POCOs aus einer Datenbank zu erstellen. Der Code funktioniert, außer wenn er auf einen Nullwert in der Datenbank trifft. Wenn zum Beispiel die Spalte Vorname in der Datenbank einen Nullwert enthält, wird eine Ausnahme ausgelöst.

employee.FirstName = sqlreader.GetString(indexFirstName);

Wie kann man in dieser Situation am besten mit Nullwerten umgehen?

4voto

Usman Ali Punkte 708

Anleitung zur Erstellung von Hilfsmethoden

Für String

private static string MyStringConverter(object o)
    {
        if (o == DBNull.Value || o == null)
            return "";

        return o.ToString();
    }

Verwendung

MyStringConverter(read["indexStringValue"])

Für Int

 private static int MyIntonverter(object o)
    {
        if (o == DBNull.Value || o == null)
            return 0;

        return Convert.ToInt32(o);
    }

Verwendung

MyIntonverter(read["indexIntValue"])

Für Datum

private static DateTime? MyDateConverter(object o)
    {
        return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
    }

Verwendung

MyDateConverter(read["indexDateValue"])

Hinweis: für DateTime deklarieren Sie varialbe als

DateTime? variable;

3voto

Rhys Jones Punkte 5158

Es gibt hier viele Antworten mit nützlichen Informationen (und einigen falschen Informationen), die ich gerne zusammenfassen möchte.

Die kurze Antwort auf die Frage ist, auf DBNull zu prüfen - in diesem Punkt sind sich fast alle einig :)

Anstatt eine Hilfsmethode zu verwenden, um nullbare Werte pro SQL-Datentyp zu lesen, ermöglicht uns eine generische Methode, dieses Problem mit viel weniger Code zu lösen. Allerdings kann man nicht eine einzige generische Methode sowohl für nullbare Werttypen als auch für Referenztypen verwenden, dies wird ausführlich in Nullbarer Typ als allgemeiner Parameter möglich? y C# generische Typbeschränkung für alles, was nullbar ist .

Also, im Anschluss an die Antworten von @ZXX und @getpsyched wir am Ende mit diesem, 2 Methoden für immer nullable Werte und ich habe eine 3. für nicht-null-Werte hinzugefügt (es vervollständigt die Menge basierend auf Methode Benennung).

public static T? GetNullableValueType<T>(this SqlDataReader sqlDataReader, string columnName) where T : struct
{
    int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
    return sqlDataReader.IsDBNull(columnOrdinal) ? (T?)null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}

public static T GetNullableReferenceType<T>(this SqlDataReader sqlDataReader, string columnName) where T : class
{
    int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
    return sqlDataReader.IsDBNull(columnOrdinal) ? null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}

public static T GetNonNullValue<T>(this SqlDataReader sqlDataReader, string columnName)
{
    int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
    return sqlDataReader.GetFieldValue<T>(columnOrdinal);
}

Ich verwende normalerweise Spaltennamen, ändern Sie diese, wenn Sie Spaltenindizes verwenden. Anhand dieser Methodennamen kann ich erkennen, ob ich erwarte, dass die Daten löschbar sind oder nicht. Das ist sehr nützlich, wenn man sich Code ansieht, der vor langer Zeit geschrieben wurde.

Tipps;

  • Durch das Fehlen von löschbaren Spalten in der Datenbank wird dieses Problem vermieden. Wenn Sie Kontrolle über die Datenbank haben, sollten Spalten nicht null sein, indem Standard und nur bei Bedarf löschbar sein.
  • Datenbankwerte nicht verzerren mit dem C#-Operator 'as', denn wenn der Cast falsch ist, wird er stillschweigend null zurückgeben.
  • Mit einer Standardwertausdruck wird sich ändern Datenbank-Nullwerte in Nicht-Nullwerte für Werttypen wie int, datetime, Bit usw.

Schließlich, beim Testen der oben genannten Methoden über alle SQL Server-Datentypen entdeckte ich, dass Sie nicht direkt ein char[] von einem SqlDataReader erhalten können, wenn Sie ein char[] möchten, müssen Sie eine Zeichenfolge erhalten und ToCharArray() verwenden.

2voto

Raghav Punkte 7357

Hier ist Hilfsklasse, die andere verwenden können, wenn sie auf @marc_s Antwort benötigen:

public static class SQLDataReaderExtensions
    {
        public static int SafeGetInt(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.IsDBNull(fieldIndex) ? 0 : dataReader.GetInt32(fieldIndex);
        }

        public static int? SafeGetNullableInt(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.GetValue(fieldIndex) as int?;
        }

        public static string SafeGetString(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.IsDBNull(fieldIndex) ? string.Empty : dataReader.GetString(fieldIndex);
        }

        public static DateTime? SafeGetNullableDateTime(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.GetValue(fieldIndex) as DateTime?;
        }

        public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName)
        {
            return SafeGetBoolean(dataReader, fieldName, false);
        }

        public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName, bool defaultValue)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.IsDBNull(fieldIndex) ? defaultValue : dataReader.GetBoolean(fieldIndex);
        }
    }

2voto

Alison Niu Punkte 54

In c# 7.0 können wir :

var a = reader["ERateCode"] as string;
var b = reader["ERateLift"] as int?;
var c = reader["Id"] as int?;

und behält daher den Wert Null, wenn dies der Fall ist.

2voto

Conner Punkte 303

Ich habe mein Bestes getan, um die Field Methode von DataTable . https://docs.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.field

Es wird geworfen, wenn Sie versuchen, eine DBNull.Value zu einem nicht-nullbaren Typ. Andernfalls konvertiert es DBNull.Value a null .

Ich habe es nicht vollständig getestet.

public static T Field<T>(this SqlDataReader sqlDataReader, string columnName)
{
    int columnIndex = sqlDataReader.GetOrdinal(columnName);
    if (sqlDataReader.IsDBNull(columnIndex))
    {
        if (default(T) != null)
        {
            throw new InvalidCastException("Cannot convert DBNULL value to type " + typeof(T).Name);
        }
        else
        {
            return default(T);
        }
    }
    else
    {
        return sqlDataReader.GetFieldValue<T>(columnIndex);
    }
}

Verwendung:

string fname = sqlDataReader.Field<string>("FirstName");
int? age = sqlDataReader.Field<int?>("Age");
int yearsOfExperience = sqlDataReader.Field<int?>("YearsEx") ?? 0;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X