Performante Lösung zum Speichern von vielen Datensätzen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    jo, liegt iwie an deine vm-Klasse, wo jede Property umlenkt auf die Model-Klasse.
    Ich hab mal die Modelse abgespeichert statt der VMs - ging ratzfatz:

    VB.NET-Quellcode

    1. Dim mdl = InhaltGesamt.Select(Function(x) x.ModelObjekt).ToList
    2. Using sw = New StreamWriter(sFile & "2.json")
    3. ser.Serialize(sw, mdl)
    4. End Using
    Echt jetzt? Da wär ich nie drauf gekommen, das hat mir damals Nofear23m so beigebracht das so zu machen. Hab ich bis heut nicht ganz geschnallt warum er das jetzt so macht...

    Muss ich gleich morgen mal umschreiben. Liegt wahrscheinlich daran, dass die Projektmappe so strukturiert ist dass sie jeweils für Model, View und ViewModel inne extra dll kompiliert. Musst mal im Ausgabeordner gucken da siehst dus...
    @ErfinderDesRades

    Kommando zurück, die Lösung ist das anscheinend noch nicht...

    Denn: Das geht zwar schneller, aber man bekommt am Ende 5486 Datensätze gefüllt mit Nullen abgespeichert... Ich verstehe nicht warum, denn in der MP3FileInfoVM wird das doch befüllt...:

    VB.NET-Quellcode

    1. Public Sub New(varDateiname As String, varTracknummer As String, varInterpret As String, varAlbum As String, varMusiktitel As String, varDauer As TimeSpan, varJahr As String, varStream As Boolean, varGenre As String, varIsFavorite As Boolean, varCoverArtPfad As String, varBPM As Integer, varKey As String, varTakt As String)
    2. ModelObjekt = New Model.MP3FileInfo(varDateiname, varTracknummer, varInterpret, varAlbum, varMusiktitel, varDauer, varJahr, varStream, varGenre, varIsFavorite, varCoverArtPfad, varBPM, varKey, varTakt)


    Also entweder wir finden raus, warum ModelObjekt voll mit Nullen ist und probierens dann nochmal oder ich muss tatsächlich umsteigen auf SQLite oder sowas in der Art.

    Was ich schon probiert hab ist diesesMP3FileInfo-Model komplett rauszuwerfen und anstattdessen in den Gettern und Settern auf Private Variablen direkt in MP3FileInfoVM zu verweisen. Da komm ich auch wieder auf meine 13 Sekunden, selbst wenn ich die RaisePropertyChangeds rauswerfe...

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

    Kann es sein, dass hier die Zuweisung des Strings einfach viel zu viel Daten (und somit Zeit) in Anspruch nimmt?

    ​Dim ZuSpeicherndeDTB As String = JsonConvert.SerializeObject(InhaltGesamt)

    Ich habe auch mal größere Dateien vom reMarkable (Strokes, Points, Colors) etc. mit Strings zusammengeklöppelt. Das ging gut, solange die Strings nicht all zu lange waren.
    Habe dann mit StringBuilder gearbeitet, was merklich schneller ging.

    Versuche einmal ​JsonConvert.SerializeObject(InhaltGesamt) ohne die Zuweisung der Funktion zum String auszuführen und teste dann die Zeit.
    Dann findest Du ganz schnell heraus, ob es an der Stringzuweisung (Datenmenge) oder an der Funktion selbst liegt.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @dive26

    Okay das ist schon mal 3-4 Sekunden schneller ohne dass ich den String der Variable zuweise. Immerhin etwas.

    Ich probier jetzt auch noch die Tipps aus Post 7 von @VB1963 aus.

    Man bemerke: Das Komische an sich ist, dass ich mit der Konsolenanwendung (Post 8) unter 1 Sekunde liege, in der WPF MVVM-Version (Post 20) aber bei 13 Sekunden...

    Edit:

    @VB1963

    Ich brauch da bisschen Hilfe mit dem JSONTextWriter. Hier findet man die Docs, die machen mich aber auch nicht schlauer. Ich glaube das Problem ist, dass ich nicht nur ein Objekt habe, sondern eine ObservableCollection(Of Object)....

    Das hab ich bis jetzt:

    VB.NET-Quellcode

    1. Private Function ToJson(OC As ObservableCollection(Of MP3FileInfoVM)) As String
    2. Dim sb As StringBuilder = New StringBuilder()
    3. Dim sw As StringWriter = New StringWriter(sb)
    4. Using writer As JsonTextWriter = New JsonTextWriter(sw)
    5. writer.Formatting = Formatting.Indented
    6. writer.WriteStartObject() 'bei dieser Zeile bin ich mir unsicher ob die da hinmüssen oder woanders oder ob ich da komplett andere Methoden nehmen muss
    7. For Each dataset In OC 'muss ich das mit einer Schleife machen?
    8. writer.WritePropertyName("Dateiname")
    9. writer.WriteValue(dataset.Dateiname)
    10. writer.WritePropertyName("Tracknummer")
    11. writer.WriteValue(dataset.Tracknummer)
    12. writer.WritePropertyName("Interpret")
    13. writer.WriteValue(dataset.Interpret)
    14. writer.WritePropertyName("Album")
    15. writer.WriteValue(dataset.Album)
    16. writer.WritePropertyName("Musiktitel")
    17. writer.WriteValue(dataset.Musiktitel)
    18. writer.WritePropertyName("Dauer")
    19. writer.WriteValue(dataset.Dauer)
    20. writer.WritePropertyName("Jahr")
    21. writer.WriteValue(dataset.Jahr)
    22. writer.WritePropertyName("Stream")
    23. writer.WriteValue(dataset.Stream)
    24. writer.WritePropertyName("Genre")
    25. writer.WriteValue(dataset.Genre)
    26. writer.WritePropertyName("IsFavorite")
    27. writer.WriteValue(dataset.IsFavorite)
    28. writer.WritePropertyName("CoverArtPfad")
    29. writer.WriteValue(dataset.CoverArtPfad)
    30. writer.WritePropertyName("BPM")
    31. writer.WriteValue(dataset.BPM)
    32. writer.WritePropertyName("Key")
    33. writer.WriteValue(dataset.Key)
    34. writer.WritePropertyName("Takt")
    35. writer.WriteValue(dataset.Takt)
    36. Next
    37. writer.WriteEnd() 'bei diesen zwei Zeilen auch
    38. writer.WriteEndObject()
    39. Return sb.ToString
    40. End Using
    41. End Function


    Edit2:
    Hab noch das hier gefunden und probiers damit mal. Jetzt muss ich noch rausfinden wie man verschachtelte Werte "jsonisiert"... :)

    aspdotnet-suresh.com/2017/01/j…-in-csharp-vbnet.html?m=1

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

    Schreib dir eine Klasse welche diese Liste als Property beinhaltet und de-/serialisiere diese. Viel einfacher als
    manuell irgendwas zu schreiben.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @mrMo

    Auf was beziehst du dich jetzt? Auf die Verschachtelung?

    Ich mach das ja manuell aus dem Grund weil das ja laut Link in Post 7 schneller sein soll, was ja der Grund für das Ganze Schlamassel ist...

    Edit: Hiermit gehts unter 1 Sekunde, die verschachtelten Werte hab ich aber aussen vor gelassen...

    Hat jemand ne Idee wie ich das implementiren kann? In den Docs hab ich nur was von .WriteStartArray() gefunden, ich hab ja aber OCs...:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Function ToJson(OC As ObservableCollection(Of MP3FileInfoVM)) As String
    2. Dim sb As StringBuilder = New StringBuilder()
    3. Dim sw As StringWriter = New StringWriter(sb)
    4. Using writer As JsonTextWriter = New JsonTextWriter(sw)
    5. For Each dataset In OC
    6. writer.WriteStartObject()
    7. writer.WritePropertyName("Dateiname")
    8. writer.WriteValue(dataset.Dateiname)
    9. writer.WritePropertyName("Tracknummer")
    10. writer.WriteValue(dataset.Tracknummer)
    11. writer.WritePropertyName("Interpret")
    12. writer.WriteValue(dataset.Interpret)
    13. writer.WritePropertyName("Album")
    14. writer.WriteValue(dataset.Album)
    15. writer.WritePropertyName("Musiktitel")
    16. writer.WriteValue(dataset.Musiktitel)
    17. writer.WritePropertyName("Dauer")
    18. writer.WriteValue(dataset.Dauer)
    19. writer.WritePropertyName("Jahr")
    20. writer.WriteValue(dataset.Jahr)
    21. writer.WritePropertyName("Stream")
    22. writer.WriteValue(dataset.Stream)
    23. writer.WritePropertyName("Genre")
    24. writer.WriteValue(dataset.Genre)
    25. writer.WritePropertyName("IsFavorite")
    26. writer.WriteValue(dataset.IsFavorite)
    27. writer.WritePropertyName("CoverArtPfad")
    28. writer.WriteValue(dataset.CoverArtPfad)
    29. writer.WritePropertyName("BPM")
    30. writer.WriteValue(dataset.BPM)
    31. writer.WritePropertyName("Key")
    32. writer.WriteValue(dataset.Key)
    33. writer.WritePropertyName("Takt")
    34. writer.WriteValue(dataset.Takt)
    35. writer.WriteEndObject()
    36. Next
    37. End Using
    38. Return sb.ToString
    39. End Function


    Habs hinbekommen :thumbsup:
    Man kommt damit jetzt unter 1 Sekunde und sieht so aus:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Private Function ToJson(OC As ObservableCollection(Of MP3FileInfoVM)) As String
    2. Dim sb As StringBuilder = New StringBuilder()
    3. Dim sw As StringWriter = New StringWriter(sb)
    4. Using writer As JsonTextWriter = New JsonTextWriter(sw)
    5. 'writer.Formatting = Formatting.Indented 'wenn man will wird der JSON Text auch noch schön formatiert (Zeilenumbruch nach jeder Property und Datensatz)
    6. writer.WriteRaw("[") 'dat hier muss man manuell schreiben lassen
    7. For Each dataset In OC
    8. writer.WriteStartObject()
    9. writer.WritePropertyName("TrackListID")
    10. writer.WriteValue(dataset.TrackListID)
    11. writer.WritePropertyName("IsPlayingIcon")
    12. writer.WriteValue(dataset.IsPlayingIcon)
    13. writer.WritePropertyName("Dateiname")
    14. writer.WriteValue(dataset.Dateiname)
    15. writer.WritePropertyName("Tracknummer")
    16. writer.WriteValue(dataset.Tracknummer)
    17. writer.WritePropertyName("Interpret")
    18. writer.WriteValue(dataset.Interpret)
    19. writer.WritePropertyName("Album")
    20. writer.WriteValue(dataset.Album)
    21. writer.WritePropertyName("Musiktitel")
    22. writer.WriteValue(dataset.Musiktitel)
    23. writer.WritePropertyName("Dauer")
    24. writer.WriteValue(dataset.Dauer)
    25. writer.WritePropertyName("Jahr")
    26. writer.WriteValue(dataset.Jahr)
    27. writer.WritePropertyName("Stream")
    28. writer.WriteValue(dataset.Stream)
    29. writer.WritePropertyName("Genre")
    30. writer.WriteValue(dataset.Genre)
    31. writer.WritePropertyName("IsFavorite")
    32. writer.WriteValue(dataset.IsFavorite)
    33. writer.WritePropertyName("CoverArtPfad")
    34. writer.WriteValue(dataset.CoverArtPfad)
    35. writer.WritePropertyName("BPM")
    36. writer.WriteValue(dataset.BPM)
    37. writer.WritePropertyName("Key")
    38. writer.WriteValue(dataset.Key)
    39. writer.WritePropertyName("Takt")
    40. writer.WriteValue(dataset.Takt)
    41. writer.WritePropertyName("CueMarkers")
    42. If dataset.CueMarkers IsNot Nothing Then
    43. writer.WriteStartArray()
    44. For Each CueMarker In dataset.CueMarkers
    45. writer.WriteValue(CueMarker)
    46. Next
    47. writer.WriteEndArray()
    48. End If
    49. writer.WriteEndObject()
    50. writer.WriteRaw(",") 'dat hier muss man manuell schreiben lassen
    51. Next
    52. writer.WriteRaw("]") 'dat hier muss man manuell schreiben lassen
    53. End Using
    54. Return sb.ToString
    55. End Function


    Jetzt muss ichs erst noch im grossen Projekt testen, v.a. die Property CueMartkers, dass die auch so gespeichert werden wie es sein soll, aber ich bin guter Dinge...

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

    kafffee schrieb:

    ... man bekommt am Ende 5486 Datensätze gefüllt mit Nullen abgespeichert....
    bei mir nicht.
    ich vermute, du versuchst die abgespeicherten Modelse dann in ViewModelse zu deserialisieren.
    Aber ein Model ist kein Viewmodel.

    achmist - ich hab hier ja nur die Console-Version am Wickel.



    jetzt nochmal unter wpf getestet - jo, kein problem.

    Beiträge zusammengeführt. ~Thunderbolt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thunderbolt“ ()

    Ich glaub ich weiss warum das bei der Konsolenanwendung so schnell ging und bei der MVVM-Version nicht.

    Zum Einen, ja, wenn man das manuell serialisiert geht's wahrscheinlich bisschen schneller - lässt sich jetzt aber schlecht testen.

    Zum Anderen hat das manuelle Serialisieren ja glaub ich den Vorteil, dass du aussuchen kannst welche Properties mit einbezogen werden. Muss ich aber noch genau testen. Jetzt hat dieses MP3FileInfoVM noch aber zwei vererbte Properties: "IsInDesignMode" und "VMIsBusy" oder so, die beim automatisch Serialisieren halt miteinbezogen werden, obwohl es absoluter Schwachsinn ist, die mit zu speichern, da ich die wenn überhaupt nur zur Laufzeit brauch. Ich muss mir das nochmal genau anschauen aber die ham wahrscheinlich in ihren Getter recht zeitintensiv en Code drin...
    Das wird wohl der Hauptfehler gewesen sein.

    Jetzt muss ich noch im Hauptprogramm testen, ob und wie das mit den verschachtelten Properties funktioniert, hab aber schon eine Idee wie und poste dann das Ergebnis nochmal hier.
    jo, so Sachen schliesst man durch Attribute von der Serialisierung aus.

    Und stimmt: Da jedesmal Process.GetCurrentProcess() aufzurufen ist evtl. unperformant.
    Ansonsten verwende ich ja eine IsInDesignmode-Variante, die Shared ist.

    Aber das wirds nicht sein, weil die Prop ist ja Readonly.



    Frage ist auch, obs ühaupt richtig ist, das Viewmodel zu speichern. Nach reiner Lehre ist nur das Model zu speichern.

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

    So, jetzt kommt gleich das nächste Folgeproblem ?(

    Ich habe in CueMarkers zwei Eigenschaften Farbe As Windows.Media.Color und SampleBrush As Windows.Media.SolidColorBrush.

    Diese Typen unterstützt der JsonTextWriter aber nicht. Also hab ich beim Serialisieren ein .ToString angehängt:

    VB.NET-Quellcode

    1. writer.WritePropertyName("Farbe")
    2. writer.WriteValue(CueMarker.Farbe.Farbe.ToString)
    3. writer.WritePropertyName("SampleBrush")
    4. writer.WriteValue(CueMarker.Farbe.SampleBrush.ToString)


    Funktioniert. Bloss wenn ich dann deserialisiere:

    VB.NET-Quellcode

    1. Dim ser = New JsonSerializer
    2. Using rd = New System.IO.StreamReader(MainModule.Arbeitsverzeichnis & "\database\musicdata.dtb"), jrd = New JsonTextReader(rd)
    3. MainModule.InhaltGesamt = ser.Deserialize(Of ObservableCollection(Of MP3FileInfoVM))(jrd)
    4. End Using


    Kommt ein Fehler wegen falschen Datentyp. Weiss jemand vielleicht wie ich das umgehen kann? Etwa auch manuell deserialisieren? Hab dafür bis jetzt leider noch kein Beispielcode gefunden...
    Kannst Du nicht diese Typen vor Serialisierung in serialisierbare Typen umwandeln? Irgendwelche Integer-Pakete oder System.Drawing.Colors oder so? Und nach Desierialisierung wieder zurück? Sodass Du quasi Properties für die App hast und Properties für die Serialisierung?
    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.

    VaporiZed schrieb:

    Kannst Du nicht diese Typen vor Serialisierung in serialisierbare Typen umwandeln? Irgendwelche Integer-Pakete oder System.Drawing.Colors oder so? Und nach Desierialisierung wieder zurück? Sodass Du quasi Properties für die App hast und Properties für die Serialisierung?



    Ja genau da versuch ich ja. Aber hab schon eine bessere Lösung gefunden:

    Hab das Ganze manuelle Serialisieren wieder über den Haufen geworfen und die Properties, die ich nicht mit serialisiert haben möchte, so behandelt:

    VB.NET-Quellcode

    1. Private _isBusy As Boolean
    2. <JsonIgnore> 'das hier
    3. Public Property VMisBusy As Boolean
    4. Get
    5. Return _isBusy
    6. End Get
    7. Set
    8. _isBusy = Value
    9. RaisePropertyChanged()
    10. End Set
    11. End Property


    Mit diesem <JsonIgnore> kannst du diese Property von der Serialisierung ausnehmen. Habs getestet, ist ungefähr genauso schnell.

    Thema erledigt :thumbsup:

    Danke wie immer an alle die sich mit mir den Kopf zerbrochen haben :)