Klasse wahlweise einbeziehen

  • VB.NET
  • .NET 7–8

Es gibt 53 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Klasse wahlweise einbeziehen

    Guten Tag,

    In der Solution liegt ein Projekt "ProjectA" (Startprojekt)
    Darin habe ich eine Klasse "ClassA"
    In dieser wird auf die Klasse "ClassB" im Projekt "ProjectB" zugegriffen und dort die Sub "mySub" ausgeführt

    Die Referenzierung in ClassA:

    VB.NET-Quellcode

    1. Imports ProjectB
    2. Private Shared bq As ClassB
    3. Shared Sub New()
    4. bq = New ClassB
    5. End Sub
    6. Private Sub btn_Click ...
    7. bq.mySub()

    Die Klasse ClassB:

    VB.NET-Quellcode

    1. Public Class ClassB
    2. Private Shared ds As DataSet
    3. Shared Sub New()
    4. ds = New DataSet
    5. ds.ReadXmlSchema("mySchema.xsd")
    6. ds.ReadXml("myXml.xml", XmlReadMode.ReadSchema)
    7. End Sub
    8. Public Sub mySub
    9. ...

    Das Erstellen des typisierten DataSet ist ein zeitintensiver Resourcen fressender Vorgang, da eine riesige Xml in das ds eingelesen wird und 47 Tabellen enstehen. Der Vorgang wird zwar nur ein Mal beim Programmstart ausgeführt (Shared) und es dauert auch nur ca. 5 Sekunden, aber es wird ja nicht gerade wenig Speicher belegt. Deshalb möchte ich, dass ein Anwender auch auf das BQ-Getöns (ClassB) verzichten kann, wenn er das will. Gibt es eine Möglichkeit, es auszuschalten? Den Button zu disablen bringt mir nichts, da "ClassB" ja trotzdem immer geladen und das ds erstellt wird.

    Wenn es keine einfache Möglichkeit gibt das zu realisiern – wie wäre es, wenn ich "ClassB" aus dem Projekt "ProjectB" herauslöse und ein eigenständiges Projekt daraus mache (z.B. als DLL). Dann wüsste ich aber immer noch nicht, wie man die DLL mal einbezieht und mal nicht.

    Es wäre toll, wenn mir jemand einen Tipp geben könnte.
    Danke und Grüße
    Norbert
    Lade doch ClassB dann erst, wenn du sie brauchst. Also nicht im Konstruktor, sondern z.B. beim Button-Click, also ca. so in der Art:

    VB.NET-Quellcode

    1. Private Sub btn_Click ...
    2. If ds Is Nothing Then
    3. ds = New ClassB
    4. End If
    5. bq.mySub()


    Wenn du andere Funktionen aus der ClassB brauchst, nimmst du das Laden der Datenbank aus dem Konstruktor der ClassB und packst das in eine "Load" oder "Read" Funktion und rufst diese dann bei Bedarf auf.
    Sowas sollte dann besser nicht in den Konstruktor. Erst recht nicht im Statischen. Vielleicht fährt der schon in Zeile 2 los.
    Mach da mal einen Haltepunkt drauf.
    Aber spätestens wenn du irgendwas aus der Klasse verwendest. Eine andere statische Funktion z.B. wofür man nichtmal eine Instanz bräuchte.

    strzata schrieb:

    Das Erstellen des typisierten DataSet
    ähm - laut deines Codes erstellst du aber überhaupt kein typisiertes Dataset :(
    ein typDataset erstellt man mit dim myDts = new <ClassenNameMeinesTypDatasets>

    Also statt

    VB.NET-Quellcode

    1. Public Class ClassB
    2. Private Shared ds As DataSet
    3. Public Sub mySub
    4. ...

    muss heissen

    VB.NET-Quellcode

    1. Public Class ClassB
    2. Private Shared ds As ClassenNameMeinesTypDatasets
    3. Public Sub mySub
    4. ...

    Ihr seid wie immer hinreissend mit euren schnellen Antworten. Danke!
    Leider schnalle ichs nicht.
    laut deines Codes erstellst du aber überhaupt kein typisiertes Dataset

    Mit den typ. DS habe ich so meine Probleme. Ich hatte bewusst "typisiertes" hingeschrieben, weil ich wissen wollte, ob ihr das anmeckert. Ich dachte, wenn man das ReadSchema mit angibt, wird es typisiert. Wohl falsch. Aber was ist nun "<ClassenNameMeinesTypDatasets>"?

    Vielleicht fährt der schon in Zeile 2 los.

    Was meinst Du damit? In ClassA oder ClassB? Ich habe den Konstruktor von ClassB shared gemacht, weil das Dataset dadurch nur ein einziges Mal beim Programmstart erstellt wird. Bei weiteren Zugriffen nicht wieder.

    @Bluespide

    VB.NET-Quellcode

    1. Private Sub btn_Click ...
    2. If ds Is Nothing Then
    3. ds = New ClassB
    4. End If
    5. bq.mySub()

    Wo wird jetzt bq deklariert?
    Tut mir leid, dass ich so nervig bin. Aber ich weiss immer noch nicht, wie der Code aussehen muss, damit die Xml nicht gelesen und kein DataSet erstellt wird. Und wie kann ich ein Boolean setzen, welches das steuert?

    strzata schrieb:

    Aber was ist nun "<ClassenNameMeinesTypDatasets>"?
    Aus den bisher gegebenen Infos kann ichs nicht erraten.
    Aber zeige mir ein Screenshot von deim Dataset im Dataset-Designer, und ich sage dir, wie der <ClassenNameMeinesTypDatasets> lautet.

    oder guggemol hier, ein Screenshot von mir:

    also bei mir heisstes CarewareDataSet, und ein solches erstelle und befülle ich wie folgt:

    VB.NET-Quellcode

    1. Public Class ClassB
    2. Private Shared ds As CarewareDataSet
    3. Shared Sub New()
    4. ds = New CarewareDataSet
    5. ds.ReadXml("myXml.xml")
    6. End Sub
    7. Public Sub mySub
    8. ...





    Tja, wenn das .ReadXml 5s dauert, muss es schon eine sehr grosse Datei sein. Wie gross ist sie denn?
    Weil ansonsten dein Ansatz mit der Shared-Deklaration ist nicht ganz verkehrt.
    Allerdings das Befüllen ist NoGo.
    Da täte ich erwarten, dass deine Konstruktion vor allem schädlich ist, wenn du im Form-Designer dein <ClassenNameMeinesTypDatasets> zufügen willst.
    Weil der Form-Designer muss es bauen, und dabei wird auch der Shared Konstruktor durchlaufen, und dassis natürlich Overkill, weil im Form-Designer braucht es ja noch garnet befüllt zu sein.
    Aber dazu später.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    strzata schrieb:

    Ich habe den Konstruktor von ClassB shared gemacht
    Gut, 'du hast den gemacht' das heißt du kannst den ändern.
    Man kann einen Konstruktor nicht Shared "machen", es gibt immer einen Konstruktor und einen statischen Konstruktor. Und gerade weil man den statischen Konstruktor nicht so oft sieht, sollte man sich drüber Gedanken machen, was da abgeht.
    Damit die Klasse als Klasse im Code vorliegt, muss der Shared Konstruktor laufen, das heißt die Klasse ist nicht benutzbar ohne, dass das, was im statischen Konstruktor geschrieben steht, abläuft.
    Und meine Vermutung ist, dass in Private Shared bq As ClassB schon dieser statische Konstruktor aufgerufen werden muss. (Das passiert nur dann nicht, wenn du bq nicht nutzt, dann wird das wegkompiliert.)
    Damit eine Instanz einer Klasse vorliegt, muss der "normale" Konstruktor ablaufen.

    Wenn das DataSet nur ein einziges Mal erzeugt werden soll, schau dir das Singleton-Pattern an.
    An der Stelle wären vielleicht noch Ratschläge hilfreich, warum man ein Singleton-Pattern nicht einfach mit einer statischen Klasse totschlagen soll, das weiß ich aber selbst nicht.

    Da auch mal am Rande eine Frage von mir: Wenn ich das Singleton-Pattern auf eine Klasse anwende, stelle ich mir immer die Frage, ob alle Member dieser Klasse Shared sein sollten, also nicht nur die Instanz. Weil irgendwie hats dann ja gar keinen Sinn nicht-statische Member da drin zu haben, auf der anderen Seite macht es die Instanz großteils überflüssig, weil überall BC42025 auftaucht und das macht es dann vermutlich zum Grauen für Drittparteien. Ich schätze im oberen Absatz kommts auf dasselbe raus.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Haudruferzappeltnoch schrieb:

    Da auch mal am Rande eine Frage von mir: Wenn ich das Singleton-Pattern auf eine Klasse anwende, stelle ich mir immer die Frage, ob alle Member dieser Klasse Shared sein sollten...
    Tja, wenn alle Member Shared wären, dann bräuchte man den Singleton-Pattern nicht.
    Das kommt durchaus vor, dass man Klassen schreibt mit nur Shared Membern. (In c# kann man eine class sogar static deklarieren, dann kann sie garkeine non-static Member mehr enthalten).
    Sowas ist dann aber keine richtige Klasse, sondern was komisches, ähnlich einem vb-Module.
    Aber doch durchaus nützlich also logische Klammer für ähnliche, aber doch voneinander unabhängige Aufgaben.

    Ebenso fungiert auch eine Singleton-"Klasse" bisserl komisch, und eiglich nur als Klammer für ähnliche Aufgaben.
    Ob man nu dies nimmt oder jenes - ziemlich schnuppe.
    Wie gesagt: DataSets sind nicht meins. Alle reden davon, dass man keine Zeile Code schreiben braucht, um eins zu erstellen. Ist mir bislang nicht gelungen. Hab mal ein paar Beispiele im Netz ausprobiert, aber es ist nichts dabei rumgekommen. Scheitert schon daran, dass alles nur mit SQL DBs funktioniert. Mit MySql geht nichts. Fehlt bestimmt noch Software auf meinem Rechner. Und den DS-Designer hab ich noch nicht zu Gesicht bekommen. Nachdem ich die Xml in ein DS eingelesen hatte, habe ich händeringend nach einem Designer gesucht, der mir grafisch die internen Verbindungen der 47 Tables im DS aufzeigt. Nichts abgebissen. Schliesslich habe ich einen ganzen Tag lang versucht, die Relationen und ID-Verbindungen auf Papier zu schreiben. Wie kann man sonst das DS mit dem Designer darstellen? Ich weiss nicht, wie ich da einen Screenshot erstellen kann. Übrigens: die Xml ist 3,5 MB groß. Mich stören nicht die 5 Sekunden, sondern vielmehr der verschwendete Speicher, wenn man das Modul gar nicht nutzt und es trotzdem einkompiliert ist.

    Im Moment versuche ich die Ergebnisse aus dem DS mühevoll StepByStep zu gewinnen.

    XML-Quellcode

    1. <ehd:bq_regelung_intervall ID="AOK_Plus_BQ_ICD_2">
    2. <ehd:indikator>
    3. <!--O09%: -->
    4. <ehd:icd V="O09%" DS="G" comment=""/>
    5. </ehd:indikator>
    6. <ehd:regel prio="1">
    7. <!--Regel #O09%(ICD10)-->
    8. <ehd:bedingung>


    VB.NET-Quellcode

    1. Dim viewICD = ds.Tables("icd").DefaultView
    2. viewICD.RowFilter = "'" & value & "' Like V And indikator_id Is Not Null"
    3. If viewICD.Count = 0 Then Exit Sub
    4. Dim indikID = CInt(viewICD(0)("indikator_id"))
    5. Dim viewIndik = ds.Tables("indikator").DefaultView
    6. viewIndik.RowFilter = "indikator_id=" & indikID
    7. Dim regelungID = CInt(viewIndik(0)("bq_regelung_intervall_id"))
    8. Dim viewRegel = ds.Tables("regel").DefaultView
    9. viewRegel.RowFilter = "bq_regelung_intervall_id=" & regelungID

    bedeutet:
    value in Table "icd" suchen
    indikID gewinnen
    indikID in Table "indikator" suchen
    regelungID gewinnen
    regelungID in Table "regel" suchen

    "indikator" ist eindeutig und die damit verknüpfte "regel" muss dan weiter verarbeitet werden (Bedingungen, Prioritäten usw.)
    Es gibt 222 Indikatoren mit 222 dazu gehörenden Regeln.
    Schau mal bei EdRs VVV rein. Da gibt's genügend Infos zum schnellen Einstieg. Inklusive: Wie erstellt man ein tDS, also typisiertes DataSet. Mit Designer, also mit GUI.

    @Haudruferzappeltnoch: Singleton vs. alles Shared: Bei Singleton kannst Du durch den ersten Aufruf von GetInstance (oder wie immer auch der PseudoKonstruktor dann effektiv heißt) bestimmen, wann die Klasse das erste mal entsteht. Dann relevant, wenn sie inhaltlich ein Schwergewicht ist, wie offensichtlich hier der Fall. Bei dem »alles static/Shared«-Ansatz hat man den Klotz von Anfang an am Bein - ob man will oder nicht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Gar nicht. Das war auch nicht meine Aussage. Du hast gefragt, was es mit dem typisierten DS auf sich hat und wie man zum Designer kommt, um da seine Tabellen zu gestalten. Von einem XML-Import hatte ich nichts geschrieben. Gibt bestimmt Tools, die das können. Und vielleicht kann @ErfinderDesRades was dazu schreiben. Aber ich bin bei dem Thema raus, da ich seit Jahren nicht mehr mit tDS arbeite.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    DataSet-Designer ist wie der Form-Designer.
    Statt: 'Du willst n Button? Zieh n Buton drauf', 'Du willst ne Tabelle? Zieh ne Tabelle drauf.'

    Ein Form kann man ja auch nicht einfach fertig einlesen. Designen ist da schon noch notwendig. Das ist bei 47 Tabellen natürlich sehr mühselig, da kann ich verstehen, wenn man das alles in ein untypisiertes Konstrukt haut. Aber auch dort ist es möglich das irgendwann der Punkt kommt, wo sich das Erstellen dieser 47 Tabellen auszahlt.

    @VaporiZed Gut, dieser Unterschied ist ja auch die Krux dieses Threads.^^

    strzata schrieb:

    Scheitert schon daran, dass alles nur mit SQL DBs funktioniert. Mit MySql geht nichts.
    Ist übrigens für ein typisiertes DataSet unerheblich. Es gibt für jeden Datenbankanbieter unterschiedliche Schnittstellen. Das wird dann über OdbcConnection, SqlConnection, MySqlConnection, und ähnliche Klassen separiert. Die machen am Ende alle dasselbe, nur für einen anderen DBTyp, der im Hintergrund dient.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Dieser Thread beinhaltet ja 2 Probleme:
    1. das Erstellen des DataSet
    2. das Implementieren einer Klasse bei Bedarf

    zu 2) Hier scheint Singleton wohl die Lösung. Man macht den Konstruktor Privat, damit die Klasse nur aus sich selbst heraus instanziiert werden kann. Dann implementiert man eine Shared-Methode, die die Instanz der Klasse zurückgibt. Damit wird sie nur beim ersten Zugriff initialisiert. Und das kann ich gut steuern.

    VB.NET-Quellcode

    1. Public Class MyClass
    2. Private Shared instance As MyClass = Nothing
    3. Private Shared ReadOnly mylock As New Object()
    4. Private Sub New()
    5. End Sub
    6. Public Shared Function GetInstance() As myClass
    7. SyncLock (mylock)
    8. If instance Is Nothing Then
    9. instance = New myClass
    10. End If
    11. End SyncLock
    12. Return instance
    13. End Function
    14. End Class

    Aufruf: Dim cl As myClass = myClass.GetInstance (noch nicht getestet)

    zu 1) Stehen meine Chancen besser, wenn ich statt des DS einen XmlSerializer dranhetzen würde? Oder darf ich mal eine abgespeckte Version der Xml (500kB) hier hochladen, damit ihr mir besser zu/abraten könntet?
    Ein DataSet ist auch dann ein DataSet wenn keine Daten enthalten sind. Diese datenlose Gerippe ist, was wir hier bisher mit typisierten DataSet und DataSet-Designer versuchen zu differenzieren von der Art:
    Dim ds as New DataSet
    Auch das ist in dem Moment nur ein Gerippe, aber halt untypisiert.

    Also irgendeine Spalte mag zwar einen bestimmten Typ haben, je nach dem was da zugrunde liegt, aber im Studio kriegst du nur Object und halbgare Methoden zum hantieren mit den Daten.
    Wenn du eine Funktion mit vorhandenen Daten zur Hand hast, die du nutzt, kann man dir daran zeigen, was sich in der typisisierten Variante ändern würde. Dann kannst du absehen, ob es sich lohnt die Datenbankstruktur nachzubilden.

    Alles was du an Xml-Content hast gehört in den Daten-/Befüllungsbereich und ist unabhängig von typisiert oder untypisiert.
    Hm aja, ganz übersehen. Ja solche Suchereien, die man kaum als Sucherei identifizieren kann sind oft, was im untypisierten Fall rumkommt.
    Du bastelst erst einen View, damit du den filtern kannst, um damit einen bestimmten Datensatz aufzugreifen. Und das dann auch noch durch verschiedene Tabellen durchreichen, um einen assoziierten Datensatz zu finden.

    Das kann so aussehen im typisierten Fall (ich nehme an V ist ein Spaltenname? Und indikator_id vom Typ Integer?):

    VB.NET-Quellcode

    1. Dim indik = DS1.ICD.FirstOrDefault(Function(r) r.V.Contains(value) AndAlso indikator_id <> 0)
    2. If indik Is Nothing Then Exit Sub
    3. Dim GefundeneRegeln = DS1.Indikator.FindByindikator_id(indik.indikator_id).GetRegelRows
    Eventuell noch kürzer, das hängt von der DBStruktur / dem DataSet ab, mehr Annahmen als die obigen wollte ich nicht machen.
    Die GetChildRows und FindByKey Funktionen sind mehr oder weniger direkte Zugriff auf Datensätze und Datensätze, die in Relation zu anderen Datensätzen stehen.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Danke! Aber bist Du Dir wirklich sicher, dass es meinem Code entspricht? Kanns jetzt nicht mehr prüfen, hab 12 Stunden am Stück hinter mir.

    VB.NET-Quellcode

    1. Public Sub BehandlungsQualitaet(indikator As String, value As String)
    2. Dim viewICD = ds.Tables("icd").DefaultView
    3. viewICD.RowFilter = "'" & value & "' Like V And indikator_id Is Not Null"
    4. If viewICD.Count = 0 Then Exit Sub
    5. Dim viewIndik = ds.Tables("indikator").DefaultView
    6. Dim viewRegel = ds.Tables("regel").DefaultView
    7. Dim viewText = ds.Tables("text").DefaultView
    8. For Each rw As DataRowView In viewICD
    9. viewIndik.RowFilter = "indikator_id=" & CInt(rw("indikator_id"))
    10. viewRegel.RowFilter = "bq_regelung_intervall_id=" & CInt(viewIndik(0)("bq_regelung_intervall_id"))
    11. viewText.RowFilter = "regel_id=" & CInt(viewRegel(0)("regel_id"))
    12. Dim txt = CStr(viewText(0)("text_Text"))
    13. MessageBox.Show(txt)
    14. Next
    15. End Sub
    Bilder
    • Tab icd.png

      10,88 kB, 540×353, 8 mal angesehen
    • Tab indikator.png

      7,02 kB, 365×308, 9 mal angesehen
    • Tab regel.png

      8,26 kB, 466×357, 6 mal angesehen
    • Tab text.png

      22,67 kB, 694×358, 9 mal angesehen

    strzata schrieb:

    Aber bist Du Dir wirklich sicher, dass es meinem Code entspricht?
    Wie gesagt: Poste einen Screenshot von deim typDataset im Dataset-Designer, dann kann man Code vorschlagen, der mit hoher Wahrscheinlichkeit sofort lauffähig ist.
    Die Dataset-Schnell-Ansicht (was du gepostet hast) ist auch nicht ganz schlecht, aber die Ansicht im Designer bietet doch mehr und besser strukturierte Information.
    Weisst du überhaupt. wie du dein Dataset im DatasetDesigner öffnen kannst?: Im SolutionExplorer (ich hoffe, du weisst, was der SolutionExplorer ist) Doppelklick auf die *.xsd-Datei.

    strzata schrieb:

    Aber bist Du Dir wirklich sicher, dass es meinem Code entspricht? Kanns jetzt nicht mehr prüfen
    Wenn du meine Fragen nicht beantwortest natürlich nicht, bzw. ich schreib ja auch Erklärungen dazu, scheinen die dir etwa fernab von dem was du tust?
    Davon abgesehen, zeigt es auf jeden Fall wie viel man sich einsparen kann und wie viel verständlicher es sein kann.
    Es ging ja auch nur drum den Unterschied aufzuzeigen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()