der henry: C# Klasse/Speicher Array

Hallo,

ich bin neu in C# und habe eine Frage zu Klassen in Kombination mit Array. Eventuell ist auch mein Ansatz/Gedanke falsch.

Ich lese eine sql Datenbank aus und weiß nicht ob ich einen oder mehrere Datensätze bei der Anfrage zurück bekomme.

Ich nutze dazu eine Klasse für die Daten und "MySqlDataReader" zum auslesen der Rückgabe aus der Datenbank.

anbei Teile meines Codes

public class spsliste
		{
			public string spsname { get; set; }
			public string ip { get; set; }
			public int mpi { get; set; }
			public string spstyp { get; set; }
			public int zyclus { get; set; }
			public bool change { get; set; }
		}`
		
    static spsliste SPSliste = new spsliste();


	MySqlDataReader rdr = cmd.ExecuteReader();

		while (rdr.Read())
				{
					SPSliste.spsname = (string)rdr["spsname"];
					SPSliste.ip = (string)rdr["ip"];
					SPSliste.mpi = (sbyte)rdr["mpi"];
					SPSliste.spstyp = (string)rdr["spstyp"];
					SPSliste.change = (bool)rdr["change"];
				}
  1. Ich finde bei MySqlDataReader keinen Zähler der mir sagt ... es kommen x Datensätze zurück, wie kann ich das lösen ?

  2. Wie kann die die Klasse "SPSliste" nummerieren ??? ... z.B.

SPSliste[counter].spsname

oder

SPSliste.spsname[counter]

Vielen Dank !!!

peter
  1. Hallo Henry,

    okay, ich habe heute etwas gelernt: ein DataReader hat einen Indexer, dem man Spaltennamen übergeben kann. Ich dachte bisher immer, man könnte nur Indexpositionen angeben (und diese zur Not mit GetOrdinal vorher einsammeln).

    Anyroad - ein DataReader liefert Dir keine Anzahl. Die kennst Du erst, wenn Du das Query-Ergebnis zu Ende gelesen und mitgezählt hast. Es gibt zwar die RecordsAffected-Eigenschaft, aber laut Microsoft gilt die nur für INSERT/UPDATE/DELETE Statements. Wobei ich nicht verstehe, wie ein DataReader mit I/U/D zusammenarbeitet 🤷‍♂️

    Eine Notlösung ist eine Vorab-Query, die COUNT(*) ermittelt. Aber das würde ich nicht machen, das ist ja ein doppelter Zugriff auf die Datenbank.

    Wenn Du eine Menge von Daten vom DataReader zurückbekommst und im Zugriff halten willst, dann musst Du die auch als Menge speichern. Ein Array bietet sich nicht an, weil Du die Anzahl nicht kennst, aber mit ArrayList oder List<> kann es gehen.

    ADO.NET bietet Dir darüber hinaus auch den Typ DataTable an. Mit einem MySqlDataAdapter kannst Du eine DataTable einfach aus dem SQL Statement füllen lassen. Allerdings hast Du dann auch die ganze ADO.NET Infrastruktur am Bein und musst die DataTable vorher designen. Ich nehme an, du verwendest das MySqlConnector Nuget-Paket? Oder verwendest Du MySql.Data? Abhängig davon könnte die relevante Doku leicht unterschiedlich sein.

    Und je nachdem, ob Du eine eigene ArrayList oder List<> bildest, oder ob Du mit DataTable arbeitest, kann auch das weitere Vorgehen unterschiedlich sein. DataTables können getypt sein, d.h. du hast dann eine SPSDataTable und eine SPSDataRow, aber das erstellst Du normalerweise nicht von Hand sondern mit den entsprechenden Designer in Visual Studio. Ohne den würde ich von DataTables abraten.

    Welchen Weg gehen wir?

    Rolf

    --
    sumpsi - posui - obstruxi
  2. Jo da gibt es schon noch das ein oder andere Verständnisproblem 😉

    Würde dir dringend die "C# coding conventions" empfehlen. Wenigstens grob, damit du bei der Namensgebung nicht unnötigerweise alles anders machst als der Rest der Welt.

    Was du class spsliste nennst, hält so wie du es implementiert hast die Einträge einer Zeile aus der Datenbank. Es ist keine Liste, sondern eines von vielen Elementen einer Liste. Der Name ist irreführend.
    Das solltest du SpsItem (oder so, jedenfalls Einzahl) nennen.

    static spsliste SPSliste = new spsliste(); erstellt ein einziges Objekt dieser Klasse. Es heißt als wäre es eine Liste, ist aber keine.
    In dieses eine Objekt schreibst du der Reihe nach die aus der Datenbank gelesenen Zeilen. Nach dem while stehen die Daten der letzten Zeile drin, der Rest ist weg.

    Was nu?

    List<> ist eine Liste, die mehrere Elemente aufnehmen kann.
    Wenn das die Mehrzahl im Namen hat, sieht man auch dass es um mehrere Elemente geht.

    Pro Rückgabezeile aus der Datenbank erstellst du dann ein neues SpsItem, weist dem die Daten so zu wie du es schon gemacht hast und dann hängst du das mit Add() an die Liste.

    Etwa so (ungetestet)

    List<SpsItem> spsItems = new List<SpsItem>();
    while ... {
        SpsItem item = new SpsItem();
        item.spsname = ...
        weitere Felder
    
        spsItems.Add(item);
    }
    
    1. Hallo encoder,

      ich hätte es jetzt mit struct probiert, Liast scheint aber ideal zu sein. Damit hatte ich aber noch nicht zu tun.

      Wie muss ich meine "List" initialisieren, das verstehe ich noch nicht ?

      List<SpsItem> spsItems = new List<SpsItem>();
      while ... {
          SpsItem item = new SpsItem();
          item.spsname = ...
          weitere Felder
      
          spsItems.Add(item);
      }
      

      sollte klar sein, wie sieht aber die Deklaration von spsItems aus ?

      Danke piet

      1. Hallo Henry,

        eine struct ist sowas ähnliches wie eine class, nur dass C# sie als Werttyp behandelt und nicht als Referenztyp. D.h. beim Zuweisen wird die struct inhaltlich kopiert und nicht nur eine Referenz übertragen.

        Heißt: eine struct ist kein Ersatz für einen Listen- oder Arraytyp.

        Eine struct hat auch die Eigenschaft, dass alle Felder initialisiert werden müssen. Bei einer struct SpsItem kannst Du nicht so einfach new SpsItem() aufrufen, du musst jedes Feld initialsieren. Das kann beispielsweise ein Konstruktor tun.

        wie sieht aber die Deklaration von spsItems aus ?

        So: List<SpsItem> spsItems;

        Wie muss ich meine "List" initialisieren, das verstehe ich noch nicht ?

        So: List<SpsItem> spsItems = new List<SpsItem>();

        Deklaration und Initialisierung erfolgen in einer Zeile. Genau so, wie Du es bei

        int a = 9;

        machst.

        Weißt Du, was generische Typen sind? Eine ArrayList enthält beliebige Objekte.
        Vorteil: Du kannst die Typen der Einträge – wie in PHP oder JavaScript – wild mischen. Nachteil: Die Typen können wild gemischt sein, und nach jedem Zugriff musst Du den Typ passend casten.

        Eine List<T> enthält NUR Werte oder Objekte vom Typ T. Eine List<int> enthält nur Integers. Eine List<SpsItem> enthält nur SpsItem-Objekte. Willst Du etwas anderes hineinschreiben, haut Dir der Compiler das um die Ohren.
        Vorteil: Du musst nicht jeden Wert casten, den Du aus einer List<T> ausliest.

        Und genau wie new SpsItem() Dir ein Objekt vom Typ SpsItem erzeugt, so erzeugt ein new List<SpsItem>() Dir ein Objekt vom Typ List<SpsItem>, als leere Liste.

        Ein List<T> ist technisch die getypte Version der ArrayList. Unter der Haube steckt ein echtes Array vom Typ T[], das von der .net Runtime nach Bedarf vergrößert wird (was ein Umkopieren bedeutet). Die Größe wird dabei jedesmal verdoppelt. Das zu Grunde liegende Array hat auch den Vorteil, dass Du in einer gefüllten Liste das i-te Element mit spsItems[i] lesen und auch durch ein anderes SpsItem in konstanter Zeit ersetzen kannst – .net muss dafür nicht die Liste durchlaufen.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf,

          vielen Dank für deine detaillierte Ausführung,sitze aber immer noch auf der Leitung ...

          Was ich nicht verstehe, wie wird dann "SpsItem" deklariert ... wie gebe die Struktur vor ?

          Danke !!

          piet

          1. Hallo Henry,

            Hä?

            Das, was in deinem ersten Post spsliste war, wird zu SpsItem umbenannt.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hallo Henry,

              Hä?

              Das, was in deinem ersten Post spsliste war, wird zu SpsItem umbenannt.

              Rolf

              Hallo Rolf,

              ... jetzt wird ein Schuh draus.🫣 Sorry, saß auf der Leitung ... jetzt verstehe ich 😉

              Danke

               piet