Dataset only -> DB / Welches System und wie?
- VB.NET
- .NET (FX) 4.0
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Es gibt 96 Antworten in diesem Thema. Der letzte Beitrag () ist von Bit-Bieger.
-
-
Läuft nun alles wie gewünscht, DataSet ist komplett mit Daten in die Datenbank integriert und laden, speichern, update etc. funzt wie es soll
Vielen Dank nochmal an @ErfinderDesRades für deine Hilfe. Dann kann das Projekt nun mit ein paar Leuten durchgetestet werden"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
@ErfinderDesRades:
Ist es möglich den folgenden Codeblock so umzubauen, dass er eine gewählte Tabelle, samt übergeordneten leert und neu befüllt aus der Datenbank heraus?
Oder reicht es nur die betroffene Tabelle zu leeren und neu zu laden?
VB.NET-Quellcode
- Public Sub CustomFill(table As DataTable, sqlAfterFrom As String, ParamArray args() As Object)
- ClearRecursive(table)
- Using adp = DirectCast(DirectCast(_Adapters(table), ICloneable).Clone, OleDbDataAdapter)
- Dim cmd = adp.SelectCommand
- cmd.CommandText &= " " & sqlAfterFrom
- For i = 0 To args.Length - 1
- cmd.Parameters.AddWithValue("@p" & i, args(i))
- Next
- _Con.Open()
- adp.Fill(table)
- _Con.Close()
- End Using
- End Sub
Ich hab' damit vor, dass vor jeder Bearbeitung eines Datensatzes die Tabellen neu initialisiert werden - anstelle des ganzen DataSets, sodass auch
die aktuellen Daten im Dataset vorhanden sind.
Also ich hab mir sowas vorgestellt wie
clearRecursive(table) -> gibt's ja schon
fillRecursive(table) -> da wüsste ich aber nicht wie ich das bauen soll
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!"Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „tragl“ ()
-
Uih - da hab ich mal einen mördermässigen Sql-Generator gebastelt, der konnte glaub sowas: "Lade diese Datensätze, und alle untergeordneten".
Aber müsste ich suchen, und untersuchen, ob das noch funktioniert.
Ist glaubich in dem Monster-Projekt, von dem ich den Namen vergessen halb - iwas wie "allgemeine Lösung...." muss ja im Datenbank-Bereich sein. -
ErfinderDesRades schrieb:
: "Lade diese Datensätze, und alle untergeordneten".
Müsste hier ja sogar umgekehrt sein - lade alle übergeordneten Tabellen und dann diese...
Aktuell ist's so eingestellt dass sobald ein Programm-Modul aufgemacht wird, das DataSet neu befüllt wird. Dadurch, dass die .mdb-Datei nun auf einem
Netzlaufwerk liegt, sorgt das für ordentlich Verzögerung. Meine Hoffnung hier ist, dass das schneller abläuft wenn eben nicht das komplette DTS neu befüllt wird,
sondern "nur" die zusammenhängenden Tabellen.
Also wenn ich sage "öffne Standort-Stammdaten" soll er die Tabelle Standort mit allen übergeordneten Tabellen neu einlesen. Das können u.U. auch sehr viele sein aber nicht alle
Wäre also super wenn du hier eine Lösung dazu hättest.ClearRecursive
gibt es ja schon, ich brauche also noch einFillRecursive
Dann könnte man beim Öffnen eines Programmteils sowas hier veranstalten:
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
tragl schrieb:
Wäre also super wenn du hier eine Lösung dazu hättest. ClearRecursive gibt es ja schon, ich brauche also noch ein FillRecursive
Nee - sowas hab ich noch nicht.
Und ist richtig - das muss auch rekursiv ermittelt werden, welches die übergeordneten Tabellen einer Tabelle sind.
Aber dassis auch recht gruselig, weil wenn du alle übergeordneten Reloadest, dann musst du dafür alle deren untergeordneten Tabellen löschen - mithin wohl ungefähr das komplette Dataset.
-
ErfinderDesRades schrieb:
dann musst du dafür alle deren untergeordneten Tabellen löschen - mithin wohl ungefähr das komplette Dataset.
simmt, soweit hab' ich nicht gedacht - dann kann ich ja auch gleich das ganze DTS reloaden. OK dann müssen die Leute damit
leben dass es erstmal länger dauert beim Öffnen von Programmteilen.
Dann zum nächsten Problem:
hier benenne ich einen Standort um - wird sich also auf einige untergeordnete Einträge in diversen Tabellen auswirken.
Trotz der Meldung werden alle zusammenhängenden Datensätze aber korrekt geändert. Warum dann die Meldung?
LG"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
-
-
Da alles nun läuft, dacht' ich mir bevor es hier langweilig wird komm ich ma mit dem nächsten Dingen
seit Umstellung auf DB wird mir nicht mehr "0", sondern "0,0000" bei Decimal-Feldern angezeigt.
In der Datenbank musste ich die Feldeinstellung auf "Währung" setzen damit meine Werte überhaupt übertragen wurden
Was kann ich tun, damit's wieder schöner aussieht? Dezimalstellenanzeige in der DB auf 2 ändern bringt leider nix"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
musste mal überprüfen, was für Werte aus der DB eingelesen werden.
Dem Aussehen nach könnten das sehr sehr kleine Werte sein, aber eben nicht0
.
Kann man sicher am Binding fixen - da kann man irgendwie einen Format-String angeben (grad vergessen wie).
(Aber scheint eh buggy zu sein, wie Access da mit Fliesskommazahlen umgeht - das war ja schon ein kranker Workaround, überhaupt von Decimal auf Currency umzusteigen) -
Spoiler anzeigen ErfinderDesRades schrieb:
Dem Aussehen nach könnten das sehr sehr kleine Werte sein, aber eben nicht 0.
Doch, die Werte sind0
- das weiß ich weil ich dem DGV ja gesagt hab': blende alles was 0 als Value hat aus.
Vielleicht muss ich mir da noch'n Textboxbehaviour bauen (dctb = DecimalTextbox) hab ich ja schon, da kann ich sowas bestimmt mit abfangen. muss ich ma testen nachher
Edit: Jo, das war's doch schon gewesen -> Zeile 5
Edit2: Oder auch nicht - auf ner anderen Form tut's das nicht, da sind die Textboxen in nem Tabcontrol auf der 2. Seite - die akualisiert er scheinbar nicht.
Schade
Lag' daran, dass in der DB "Currency" eingstellt war. Habe nun auf "Double" geändert, weil ich nur 2 nachkommastellen brauche - nu läufts
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!"Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „tragl“ ()
-
ErfinderDesRades schrieb:
vermutlich führt die DB eine ChildRow-Umbenennung aus.
Ich hätt' da die nächsteParallelitätsverletzung
, trotz deiner neuen OleDbPersistance....."Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
Spoiler anzeigen .. uuuund das nächste Problem (vermutlich steh' ich aufm Schlauch aber es will nicht klappen):
Mit der folgenden Sub lass' ich mir aus ner Bestellung die Positionen (geliefert <> bestellt) in eine TempTable packen, die soll vorher gecleared werden (Zeile 7)
Das Clearen geht schonmal nicht (code läuft durch aber in der Datenbank stacken sich die TempRows bis ins Unendliche..)
Dann kann ich indlgNeueLieferung
auswählen, welche Positionen mit welcher Menge geliefert wurden. Beim Verlassen des
Dialogs werden dann entsprechend die TempRows in die TabellePosLieferung
übertragen (Zeile 32) (soweit die Theorie) - in der Datenbank is leider nix zu finden...
an anderen Stellen klappt's mit Clear und AddXYRow - hab ich was übersehen?
Spoiler anzeigen VB.NET-Quellcode
- Private Sub neueLieferung()
- Dim bestellNr = bsBestellung.At(Of BestellungRow).ID
- Dim offenePos = Dts.Position.Where(Function(x) x.BestellID = bestellNr AndAlso x.geliefertMenge <> x.Menge)
- If Not offenePos.Count = 0 Then
- Using dlg As New dlgNeueLieferung
- Dts.Register(dlg, False)
- Dts.PosTemp.Clear()
- dlg.IDTextBox.Text = "NEU"
- dlg.ExpBestellNrTextBox.Text = bestellNr.ToString
- For Each rwOffen In offenePos
- Dts.PosTemp.AddPosTempRow(rwOffen.ID,
- rwOffen.expMitarbeiterName,
- rwOffen.expArtikelnummer,
- rwOffen.expArtikelBezeichnung,
- rwOffen.expArtikelMerkmal,
- rwOffen.expArtikelVE,
- rwOffen.Zusatz,
- rwOffen.Info,
- rwOffen.expLieferant,
- rwOffen.Menge - rwOffen.geliefertMenge,
- rwOffen.Menge,
- rwOffen.geliefertMenge)
- Next
- If dlg.ShowDialog() = DialogResult.OK Then
- Dim lt = Date.Parse(dlg._lt)
- Dim lsNr = dlg._lsNr
- Dim bemerkung = dlg._bemerkung
- 'Dim idCounter = -1 'Dts.PosLieferung.Count + 1
- For Each rwTemp In Dts.PosTemp
- Dim rwPos = Dts.Position.First(Function(x) x.ID = rwTemp.PosID)
- Dim geliefert = rwPos.geliefertMenge
- Dts.PosLieferung.AddPosLieferungRow(-1, lt, lsNr, bemerkung, rwPos, rwTemp.Menge, Date.Now, "", "")
- rwPos.geliefertMenge = geliefert + rwTemp.Menge
- Next
- End If
- End Using
- setBestellStatus()
- Dts.SaveDts()
- Else
- msgInformation("Es wurden bereits alle Positionen geliefert.")
- End If
- End Sub
auch erledigt. mit der aktuellsten Version von hier klappt das ...
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!"Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „tragl“ ()
-
@ErfinderDesRades:
Ich nochmal. Also, es läuft ja mittlerweile alles wie es soll.
Allerdings dauert das Befüllen des DataSets aus der Datenbank (weil Netzlaufwerk) verdammt lange - und ich mache mir sorgen,
dass es noch länger dauert, je mehr Daten in der Datenbank sind.
Jetzt ist es aber so, dass aktuell ALLE Daten aus der Datenbank in's DataSet und somit auch in den Arbeitsspeicher geladen werden. Die User brauchen aber nur einen Bruchteil davon (gefilterte Daten).
Gibt es eine saubere Möglichkeit beim Öffnen eines Programm-Moduls nur die geforderten Daten zu laden (das geht ja in jedem Fall) und trotzdem
das DataSet weiter zu nutzen? Also quasi statt einem BindingSource-Filter einen "LadeDatenAusDatenbank"-Filter nutzen.
Also ich stelle mir das so vor:
Beim Öffnen der Anwendung werden alle relevanten Daten geladen,
z.B. Tree, User
sowas wieDts.Fill(Tree, User)
Beim Öffnen eines Anwendungsteils (z.B. Urlaubsplanung) brauchen dann nur die Anwendungsdaten erhalten bleiben
z.B. Mitarbeiterdaten(gefiltert nach Benutzerrechten), Urlaubsplandaten(gefiltert nach Benutzerrechten)
sowas wieDts.Fill(Mitarbeiter, Urlaubsplan)
etc.
Laut meinem Kenntnisstand sollte es ja auch kein Problem sein, dass ich z.B. einen Mitarbeiter umbenenne und nicht alle abhängigen Tabellen im DataSet gefüllt sind - denn die
Datenbank ändert das ja dann selbstständig. Ist das korrekt?
Also ich ändere einen Mitarbeiternamen - in der Urlaubsplanung die gerade geöffnet ist ändert sich der Name auch (weil im DataSet geladen) und in den
Arbeitszeiten z.B. ändert sich der Name dann beim Speichern in der Datenbank (zu dem Zeitpunkt nicht im DataSet geladen)
Ich hoffe du verstehst was ich meine - damit möchte ich die Ladezeiten extrem verkürzen, aktuell macht es keinen Spaß damit zu arbeiten leider.
Die DataSet-Methode möchte ich in jedem Fall gerne beibehalten (ist extrem einfacher im Code mit typisierten Dingen zu arbeiten)
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
Hi Tragl,
wieviele Clients werden dein Programm nutzen oder vielmehr auf dein Server zugreifen um Daten zubearbeiten?
hier Lesestoff zu Client/Server
ip-insider.de/was-ist-das-client-server-modell-a-940627/
dein programm wird meiner Meinung nach mit Max 5-8 Leuten funktioniern, danach wird es eng.
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kasi“ ()
-
Aktuell sind es 5-6 Leute aber warum soll das eng werden? Die Ladezeit erhöht sich nur mit den Datenmengen in der DB. Deshalb möchte ich das verkürzen. Mit Client<-> Server bin ich vertraut aber wie schon erwähnt hab ich aktuell keine andere Möglichkeit als Access-dB-Datei auf dem Netzlaufwerk. Erst wenn die Anwendung offiziell genehmigt wird steht mir alles offen. Und dann wird die auch von 50-60 Usern genutzt. Ich brauche aber jetzt für die Testphase eine Übergangslösung"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
tragl schrieb:
Mit Client<-> Server bin ich vertraut
das ganze wiederspricht eine Client/Server Anwendung
wenn ich einen neuen Kunden anlegen will, schickt der Client die Daten zum Server, vom Server will ich
vielleicht die neue Kundennummer zurück haben oder eine Bestätigung
das er Erfolgreich angelegt wurde.
genauso könnte der Server dir mitteilen das Kunde X mit der Kundennummer 001 zur Zeit von User Xyz
seit 13:10 Uhr in Bearbeitung ist und dieser Datensatz nicht auswählbar ist
aber mit dieser Aussage ....jetzt ist es aber so, dass aktuell ALLE Daten aus der Datenbank in's DataSet und somit auch in den Arbeitsspeicher geladen werden. Die User brauchen aber nur einen Bruchteil davon (gefilterte Daten).
..kommst du langsam dahinter
-
Kasi schrieb:
das ganze wiederspricht eine Client/Server Anwendung
Ich betreibe selbst diverse Server, von daher ist mir ganz sicher bewusst wie sich Client <-> Server-Anwendungen verhalten.
tragl schrieb:
aber wie schon erwähnt hab ich aktuell keine andere Möglichkeit als Access-dB-Datei auf dem Netzlaufwerk
bedeutet: Die Anwendung habe ich geschrieben und entwickelt (mit Hilfe aus dem Forum hier). Wir sind ein Konzern, da lässt man nicht mal eben so jede Anwendung rein - besprochen wurde mit meinen Vorgesetzten, dass wir die Anwendung
mit einer Handvoll Leute ausgiebig testen und ausprogrammieren. Erst dann geht der Vorgang an die IT-Abteilung - die prüfen dann alles und dann bekomme ich Möglichkeiten alles über Server laufen zu lassen.
Dann bekomme ich einen SQL-Server zur Verfügung gestellt und meine Anwendung wird auch ab dann mit über die Citrix-Landschaft veröffentlicht (was das ganze auch mit Datenbank-Datei schon erheblich perfomanter machen würde).
Ich hoffe, das war nun verständlich genug
Ich brauche für jetzt also zwingend eine Lösung, die mit Datenbankdatei auf Netzlaufwerk funzt - und da fällt mir aktuell nix anderes zu ein als nur die Daten in's DataSet zu laden, die ich auch wirklich brauche - bzw.
die der User zu dem Zeitpunkt auch wirklich benötigt. Da eine funktionierende Berechtigungs-Steuerung einprogrammiert ist, sollte das normal kein Problem darstellen. Auch RecordLocking habe ich als primitive
Variante (Timestamp wird zur Bearbeitung auf 3 Stunden im Voraus gestellt, nach Bearbeitung wieder auf Date.Now) schon drin und das funktioniert auch ausreichend.
Edit: Falls du damit meinst, dass ich die Anwendung einmal als Client- und einmal als Serveranwendung bereitstellen sollte: vergiss' das wieder ein Datenbank-Server im
Backend genügt hierfür vollkommen.
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
du kannst Instanzen von z.b. Kunden Laden statt alle Kundendaten laden
dies würde bedeuten das eine andere Programmierung nötig ist = eine Kunden Klasse
hier eine einfache variante
du brauchst zwei forms
Form1:
VB.NET-Quellcode
- 'in Form1:
- '1x Button
- '1x Listview
- Public Class Form1
- Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
- 'Server mit SQL anfragen:
- 'Listview oder DGV mit einer SQL-Query befüllen (gefilterte Daten) die Kunden;Aufträge;Stammdaten oder
- 'was auch immer ???
- With ListView1
- .View = View.Details
- .LabelEdit = False
- .HideSelection = False
- .GridLines = True
- .FullRowSelect = True
- .Columns.Add("KundenID", 80)
- .Columns.Add("Firma", 100)
- .Columns.Add("Locked By", 100)
- .Columns.Add("Locked since", 120)
- End With
- 'gefilterte Daten aus Kundenstammdaten....
- lvwAddItem(ListView1, "001", "Behrent", "", "")
- lvwAddItem(ListView1, "002", "Becker", "", "")
- lvwAddItem(ListView1, "003", "Bosbeck", "", "")
- lvwAddItem(ListView1, "004", "Biedermann", "", "")
- 'etc....
- 'disable Button1 noch wurde nix selektiert
- Button1.Enabled = False
- 'User Information verwenden oder ???
- Debug.Print(Microsoft.Win32.Registry.CurrentUser.Name.ToString)
- Debug.Print(Environment.UserName.ToString())
- Debug.Print(SystemInformation.UserName)
- Debug.Print(System.Security.Principal.WindowsIdentity.GetCurrent().Name)
- End Sub
- Public Sub lvwAddItem(ByVal lvw As ListView, ByVal ParamArray Text() As String)
- 'Source von : https://www.vbarchiv.net/tipps/tipp_2010-listview-elegant-fuellen.html
- With lvw.Items
- .Add(New ListViewItem(Text))
- End With
- End Sub
- Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
- For Each lvItem As ListViewItem In ListView1.SelectedItems
- 'SQL Update hier und in Datenbank schreiben
- 'Locked by User = ?
- 'Locked since = Now()
- 'Record is jetzt gelockt
- lvItem.SubItems(2).Text = "Tragl"
- ' lvItem.SubItems(2).Text = Environment.UserName.ToString()
- lvItem.SubItems(3).Text = Now
- Next
- 'die Form die geöffnet werden soll
- 'hier nur ein Bsp. zur Ansicht
- Dim frm As New Form2
- For Each lvItem As ListViewItem In ListView1.SelectedItems
- frm.Text = "Kunde :" & lvItem.SubItems(0).Text
- frm.TextBox1.Text = lvItem.SubItems(0).Text
- frm.TextBox2.Text = lvItem.SubItems(1).Text
- frm.Label1.Text = lvItem.SubItems(2).Text
- frm.Label2.Text = lvItem.SubItems(3).Text
- Next
- 'normalerweise Me.Hide()
- 'Form2.Show nur um anzuzeigen was der nächste User zusehen bekommt
- frm.Show()
- End Sub
- Private Sub ListView1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ListView1.SelectedIndexChanged
- For Each lvItem As ListViewItem In ListView1.SelectedItems
- If lvItem.SubItems(2).Text > "" Then
- 'disable Button weil User "Xyz" diesen Datensatz in Bearbeitung hat
- Button1.Enabled = False
- Else
- Button1.Enabled = True
- End If
- Next
- End Sub
- End Class
Form2:
VB.NET-Quellcode
- Public Class Form2
- Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
- 'close Instanz
- Me.Close()
- End Sub
- Private Sub Form2_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
- 'Server mitteilen das Client fertig ist
- 'hier Sql um Datensatz wieder Freizuschalten
- End Sub
- End Class
bei mir können Clients höchsten 4 Instanzen öffnen
-
Ähnliche Themen
-
7 Benutzer haben hier geschrieben
- tragl (45)
- ErfinderDesRades (34)
- Kasi (8)
- MrTrebron (4)
- Akanel (3)
- Bit-Bieger (2)
- petaod (1)