2009-10-03 13 views
5

Ich verwende derzeit einen SQL-Datenleser (in vb.net), um ein Artikelobjekt über eine gespeicherte Prozedur aus einer SQL Server 2008-Datenbank zu extrahieren. Ein Teil dieser Aufgabe umfasst die beiden nachstehend aufgeführten:Wie gebe ich einen Wert an einen sqldatareader zurück, wenn der Wert null ist?

theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness")))) 
theArticle.Relevance = ((myReader.GetInt32(myReader.GetOrdinal("Relevance")))) 

Mein Problem ist, dass die Wahrhaftigkeit und Relevanz kann einen Nullwert zurückgeben und dies verursacht die Funktion umfallen.

Ich denke, ich verstehe warum. Ich frage nach einem ganzzahligen Wert (getin32) und weil NULL zurückgegeben wird, schlägt es fehl.

Wie passe ich den Nullwert aus der Datenbank an, damit er nicht umfällt?

Antwort

16

Sie können überprüfen, ob eine bestimmte Ordinalposition Null ist .IsDBNull() und dann etwas tun - z. setzen Sie den Wert auf -1 oder etwas:

int myOrdinal = myReader.GetOrdinal("Truthfullness"); 

if(myReader.IsDBNull(myOrdinal)) 
{ 
    theArticle.Truthfulness = -1; 
} 
else 
{ 
    theArticle.Truthfulness = myReader.GetInt32(myOrdinal); 
} 

Als Mike Hofer weist in seiner Antwort aus, können Sie auch alle diese Logik in eine Erweiterung Methode wickeln:

public static class SqlDataReaderExtensions 
{ 
    public static int SafeGetInt32(this SqlDataReader reader, 
            string columnName, int defaultValue) 
    { 
     int ordinal = reader.GetOrdinal(columnName); 

     if(!reader.IsDbNull(ordinal)) 
     { 
      return reader.GetInt32(ordinal); 
     } 
     else 
     { 
      return defaultValue; 
     } 
    } 
} 

und verwenden Sie dann nur, dass " SafeGetInt32" -Methode statt:

theArticle.Truthfulness = myReader.SafeGetInt32("Truthfullness", -1); 

Marc

+0

oder die Ausnahme fangen und damit umgehen – Mark

+1

Ja, könnten Sie das auch tun - aber eine Ausnahme zu vermeiden ist besser als fangen und einen ( –

+1

@marc_s: Vereinbart mit Ihrem Kommentar zu meiner Antwort. Löschen Danke, dass du es klargestellt hast. Ihr Kommentar lautete: "Ich glaube nicht, dass dies funktionieren wird, denn wenn die db-Spalte NULL ist, wird der Aufruf von .GetInt32() mit einer Ausnahme fehlschlagen - Sie erhalten keinen NULL-Wert zurück, den Sie dann in den" ?? "Operator ...." – Mahin

3

Haben Sie überprüfen, SqlDataReader.IsDBNul l Methode? Wahrscheinlich so etwas wie:

if(myReader.IsDBNull(myReader.GetOrdinal("Truthfulness")) 
theArticle.Truthfulness = string.Empty; 
else 
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness")))) 
+0

gut, string.Empty wird nicht viel Gutes tun, wenn Sie mit einem Int32-Eigenschaft beschäftigen ...... –

1

Sie wissen, dass ich die ganze Zeit in Oracle damit zu tun habe. Um den Code zu bereinigen, schrieb ich eine Reihe von Erweiterungsmethoden um den Betrieb zu vereinfachen:

using System.Data.OracleClient; 
public static class OracleDataReaderExtensions 
{ 
    public static int GetInt32(this OracleDataReader reader, string columnName, int defaultValue) 
    { 
     return reader.GetInt32(reader.GetOrdinal(columnName)) != DbNull.Value ? 
       reader.GetInt32(reader.GetOrdinal(columnName)) : 
       defaultValue; 
    } 
} 

Erstellen Sie eine separate Überlast für jeden Typ Sie zurückkehren möchten. Ich arbeite hauptsächlich mit string, int, date und dezimal. Merken Sie sich YAGNI (Sie müssen nicht mit jedem vom Lesegerät unterstützten Typ arbeiten, sondern nur mit denen, die Sie tatsächlich verwenden.)

Eine Erweiterungsklasse wie diese für SQL Server ist wirklich einfach zu schreiben und wird Ihre Arbeit VASTLY vereinfachen. Vertrau mir darauf. Würde ich dich anlügen? :)

+1

Ich glaube nicht, dass dies funktioniert, da wenn die Spalte in der Datenbank ist NULL, dann wird der Aufruf von GetInt32() eine Ausnahme verursachen. Sie können diesen Call GetInt32() nicht mit DBNull.Value vergleichen und darauf reagieren .... –

+0

Eigentlich funktioniert es. Ich benutze es jeden Tag. –

+0

Der Grund, warum es funktioniert, ist, weil wir den Kurzschluß-Operator?: Verwenden. Wenn es nicht null ist, geben wir es zurück. Andernfalls geben wir den Standardwert zurück. –

0

Hier ist, was wir auf SQLServer verwenden und es wirkt wie ein Zauber:

... 

    Dim X as Object = pbDr("TotAmt") 'dr is dim'ed as a DataReader 

... 

    Public Function pbDr(ByVal drName As String) As Object 

    Dim SQLError As SqlClient.SqlException 

    Dim IsNull As Boolean 

    Dim Ordinal, DispNbr As Integer 

    Try 
     Ordinal = dr.GetOrdinal(drName) 
     IsNull = dr.IsDBNull(Ordinal) 
     If IsNull Then 
     Dim Dbtype As String = dr.GetFieldType(Ordinal).ToString 
     If Dbtype = "System.String" Then 
      Return "" 
     ElseIf Dbtype = "System.Int32" _ 
     OrElse Dbtype = "System.Double" _ 
     OrElse Dbtype = "System.Decimal" _ 
     OrElse Dbtype = "System.Int16" Then 
      Return 0 
     Else 
      MsgBox("Print This Screen And Send To Support" _ 
      & "pbdr-Object = " & Dbtype, MsgBoxStyle.Critical) 
      Return "" 
     End If 
     Else 
     Return dr(Ordinal) 
     End If 

    Catch sqlerror 
     Call DispSQLError(SQLError, "pbDr") 
     pbDr = "" 
    End Try 

    End Function 
0

IsDBNull (int) ist in der Regel viel langsamer, dass Methoden wie GetSqlInt32 und anschließend zu DBNull.Value Vergleich oder unter Verwendung ihres own.IsNull Wie:

public static int Int32(this SqlDataReader r, int ord) 
    { 
     var t = r.GetSqlInt32(ord); 
     return t.IsNull ? default(int) : t.Value; 
    } 

Ich habe versucht, ein paar Vorlagen-Lösungen, aber bis jetzt vergeblich. Das Problem ist, dass alle Sql-Typen (SqlInt32 here) tatsächlich Strukturen sind und während sie alle .Value -Eigenschaft C# haben keine echten Vorlagen, um das zu handhaben. Außerdem haben sie ihre eigene INullable-Schnittstelle, die nur .IsNull hat und nicht kompatibel mit Nylable <> ist.

Ich vermute, dass man einen vollständigen Satz von SQL-Typen als C# -Templates oder ICOnvertible zu ihnen hinzufügen müsste, um nur ein oder zwei Template-Methoden zu haben.

Wenn jemand vielleicht eine Idee, mit einem funktionellen Trick hat oder zwei sprechen :-)

1

Diese generische Version von Nutzen sein kann:

private T ValueOrDefault<T>(System.Data.IDataReader rdr, string columnName) 
    { 
     T vod = default(T); 
     try 
     { 
      int idx = rdr.GetOrdinal(columnName); 
      if (!rdr.IsDBNull(idx)) 
       return (T)rdr[idx]; 
     } 
     catch (IndexOutOfRangeException) { } 

     return vod; 
    } 

kann erweitert werden InvalidCastException zu fangen, oder Convert verwenden .ChangeType anstelle des Castings?

+0

Ich mag diese Option mit Ausnahme der IndexOutOfRangeException catch-Anweisung. Ich würde denken, dass Sie so schnell wie möglich wissen möchten, ob sich die Schemastruktur verändert hat, anstatt Standardwerte auf andere Teile Ihres Systems zu übertragen. –

Verwandte Themen