Autor Beitrag
JohnDyr
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Fr 04.01.19 17:04 
Moin,

meine Spalte kann entweder int oder null sein. Dafür habe ich folgenden Code geschrieben, welcher null-safe sein soll:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
internal static int GetLoaderFreightAmount1(int id)
{
  SqlCommand cmd = new SqlCommand("SELECT LoaderFreightAmount1 FROM [Order] WHERE ID = @id", Connection);
  cmd.Parameters.AddWithValue("@id", id);
  return cmd.ExecuteScalar() == DBNull.Value ? 0 : (int)cmd.ExecuteScalar();
}


Im Falle eines strings habe ich folgenden Code geschrieben:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
        
internal static string GetLoaderRef1(int id)
{
  SqlCommand cmd = new SqlCommand("SELECT LoaderRef1 FROM [Order] WHERE ID = @id", Connection);
  cmd.Parameters.AddWithValue("@id", id);
  return Convert.ToString(cmd.ExecuteScalar());
}


Würdet ihr das auch so machen? Geht das noch eleganter?


Zuletzt bearbeitet von JohnDyr am Fr 04.01.19 17:08, insgesamt 2-mal bearbeitet
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3951
Erhaltene Danke: 812

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Fr 04.01.19 17:50 
Im ersten Fall solltest du cmd.ExecuteScalar() aber nur einmalig ausführen lassen (also Rückgabewert in einer Variablen speichern und vergleichen).
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Fr 04.01.19 18:16 
Stimmt. Habe ich geändert.

ausblenden C#-Quelltext
1:
2:
object res = cmd.ExecuteScalar(); 
return res == DBNull.Value? 0 : (double) res;


So oder?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4401
Erhaltene Danke: 897


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: So 06.01.19 14:53 
Wenn in der Datenbank nicht mal die passende Zeile gefunden wird liefert ExecuteScalar null zurück.
Z.B. also wenn in deiner GetLoaderFreightAmount1 Methode die id nicht existiert.

In dem Fall wird der cast knallen. Null lässt sich nicht nach int oder double casten.
Du mußt leider nicht nur auf DBNull.Value testen sondern auch auf null.

Für diesen Beitrag haben gedankt: JohnDyr
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: So 06.01.19 15:33 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Wenn in der Datenbank nicht mal die passende Zeile gefunden wird liefert ExecuteScalar null zurück.
Z.B. also wenn in deiner GetLoaderFreightAmount1 Methode die id nicht existiert.

In dem Fall wird der cast knallen. Null lässt sich nicht nach int oder double casten.
Du mußt leider nicht nur auf DBNull.Value testen sondern auch auf null.


Das ist ja blöd... nun gut, habe es jetzt so gelöst:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
object res = cmd.ExecuteScalar();
  if (res == null || res == DBNull.Value)
  {
    return 0;
  }
  return (int) res;
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3951
Erhaltene Danke: 812

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mo 07.01.19 10:25 
Das geht aber auch per ? : Operator:
ausblenden C#-Quelltext
1:
2:
object res = cmd.ExecuteScalar();
return res == null || res == DBNull.Value? 0 : (int)res;

Oder man könnte daraus dann auch gleich eine generische Methode machen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
T Exec<T>(...) where T : IConvertible
{
  // ...
  object res = cmd.ExecuteScalar(); 
  return res == null || res == DBNull.Value? default(T) : (T)res;
}

(jedoch gefällt mir die Rückgabe von 0 (bzw. default(T)) bei einem Fehler nicht so sehr)
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4401
Erhaltene Danke: 897


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 07.01.19 11:47 
Zitat:
(jedoch gefällt mir die Rückgabe von 0 (bzw. default(T)) bei einem Fehler nicht so sehr)


Ob das ein Fehler ist ein wenig Definitionssache. "Nicht vorhanden" nicht von "es ist null" zu unterscheiden ist aber definitiv unschön.
Es konterkariert die Existenz von DBNull und es hat einen guten Grund warum es den Typ gibt auch wenn die Implementierung aufgrund des Alters von ADO.Net unschön ist.

Hier ist es jetzt sogar so das man 0 nicht von NULL nicht von nicht existent unterscheiden kann. Da es aber hier keine allgemeine Lösung ist sondern für ein bestimmtes Feld
einer bestimmten Tabelle könnte ich damit leben wenn das für dieses Feld ok ist. Man sollte das nur nicht für ein Standardmuster halten und immer so anwenden.

Für diesen Beitrag haben gedankt: JohnDyr
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3951
Erhaltene Danke: 812

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mo 07.01.19 13:37 
Ja, "Fehler" ist Definitionssache.

Evtl. wäre aber dann Nullable<T> (kurz T?) hier besser (auch wenn man hier wieder explizit abfragen müßte, aber wenigstens wäre es typsicher - gegenüber nur object zurückzugeben):
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
T? Exec<T>(...) where T : struct
{
  // ...
  object res = cmd.ExecuteScalar(); 
  return res == null || res == DBNull.Value? default(T?) : (T)res;
}

Nachträglich könnte man dann aber auch GetValueOrDefault() darauf aufrufen.

Für diesen Beitrag haben gedankt: JohnDyr