Code zur Anzeige von Daten aus DataSet optimieren (Ausführung dauert zu lange)

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

Es gibt 98 Antworten in diesem Thema. Der letzte Beitrag () ist von DerSmurf.

    Danke @EaranMaleasi für deinen EInschub. Das finde ich enorm hilfreich! :o)

    @ErfinderDesRades
    Ich habe erstmal nur ein bisschen Code erstellt, um sicherzugehen, dass ich deine Vorgehensweise korrekt umgesetzt habe.

    ErfinderDesRades schrieb:

    Ich würde die Rekorde beim Einlesen des Datasets ausrechnen und merken.
    Man kann innerhalb des Datasets ja zusätzlichen Code anlegen - auch Variablen, die die Rekorde merken.


    Den alten Code habe ich in der hochgeladenen Solution gelassen, aber auskommentiert - um eben nicht vom ooben erwähnten abzulenken.
    Im nicht auskommentierten Code fehlt noch die höchste Tageseinnahme für jede Warengruppe - aber die ließe sich ja - sofern korrekt umgesetzt - auf die gleiche Art einbauen.

    Den alten Code zur Jahresauswertung habe ich nicht eingebaut, da dieser einfach schlecht ist.
    Ich habe diesen mal hinter folgendem Spoiler versteckt - er lässt sich in der Demosulution in die frmMain einkopieren und ist dort lauffähig.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Sub zum erstellen der Monatsrekorde
    2. Private Sub DrawControlsMonthlyRecords()
    3. 'Anzahl der Warengruppen ermitteln
    4. Dim GroupCount As Integer
    5. GroupCount = DtsSettings.ProductGroup.Count
    6. If GroupCount = 0 Then Exit Sub
    7. Dim yPosition As Integer = 60 'y = unten / 570
    8. 'Controls für Kunden und Monatsumsatz anlegen
    9. 'Prüfen ob Umsätze vorhanden sind
    10. If DtsSettings.DailyIncome.Count = 0 Then Exit Sub
    11. 'Umsatz und Kundenrekorde suchen
    12. Dim strRecord As String = GetMonthlyIncomeAndCustomersRecord()
    13. Dim arrRecord() As String = strRecord.Split("|")
    14. 'Label für Beschriftung - Gesamtusatzrekord
    15. Dim LBLLabelIncome = New System.Windows.Forms.Label
    16. With LBLLabelIncome
    17. .Location = New System.Drawing.Point(490, yPosition)
    18. .Font = New Font("Microsoft Sans Serif", 12)
    19. .TextAlign = ContentAlignment.MiddleRight
    20. .Name = "LBLLabelMonthlyIncome"
    21. .Size = New System.Drawing.Size(200, 20)
    22. .Text = "Monatseinnahme"
    23. .Visible = True
    24. End With
    25. 'Label für Gesamtusatzrekord
    26. Dim LBLRecordIncome = New System.Windows.Forms.Label
    27. With LBLRecordIncome
    28. .Location = New System.Drawing.Point(700, yPosition)
    29. .Font = New Font("Microsoft Sans Serif", 12)
    30. .TextAlign = ContentAlignment.MiddleRight
    31. .Name = "LBLRecordMonthlyIncome"
    32. .Size = New System.Drawing.Size(120, 20)
    33. .Text = arrRecord(0)
    34. .Visible = True
    35. End With
    36. 'Label für Rekord Datum - Gesamtumsatz
    37. Dim LBLRecordIncomeDate = New System.Windows.Forms.Label
    38. With LBLRecordIncomeDate
    39. .Location = New System.Drawing.Point(830, yPosition)
    40. .Font = New Font("Microsoft Sans Serif", 12)
    41. .TextAlign = ContentAlignment.MiddleLeft
    42. .Name = "LBLRecordIncomeMonth"
    43. .Size = New System.Drawing.Size(150, 20)
    44. .Text = "im " & arrRecord(1)
    45. .Visible = True
    46. End With
    47. 'Controls auf die Form malen
    48. Me.Controls.Add(LBLLabelIncome)
    49. Me.Controls.Add(LBLRecordIncome)
    50. Me.Controls.Add(LBLRecordIncomeDate)
    51. yPosition += 30
    52. 'Label für Beschriftung - Gesamtkunden
    53. Dim LBLLabelCustomers = New System.Windows.Forms.Label
    54. With LBLLabelCustomers
    55. .Location = New System.Drawing.Point(490, yPosition)
    56. .Font = New Font("Microsoft Sans Serif", 12)
    57. .TextAlign = ContentAlignment.MiddleRight
    58. .Name = "LBLLabelMonthlyCustomers"
    59. .Size = New System.Drawing.Size(200, 20)
    60. .Text = "Kunden:"
    61. .Visible = True
    62. End With
    63. 'Label für Gesamtkundenrekord
    64. Dim LBLRecordCustomers = New System.Windows.Forms.Label
    65. With LBLRecordCustomers
    66. .Location = New System.Drawing.Point(700, yPosition)
    67. .Font = New Font("Microsoft Sans Serif", 12)
    68. .TextAlign = ContentAlignment.MiddleRight
    69. .Name = "LBLMonthlyRecordCustomers"
    70. .Size = New System.Drawing.Size(120, 20)
    71. .Text = arrRecord(2)
    72. .Visible = True
    73. End With
    74. 'Label für Rekord Datum - Kunden
    75. Dim LBLRecordCustomersDate = New System.Windows.Forms.Label
    76. With LBLRecordCustomersDate
    77. .Location = New System.Drawing.Point(830, yPosition)
    78. .Font = New Font("Microsoft Sans Serif", 12)
    79. .TextAlign = ContentAlignment.MiddleLeft
    80. .Name = "LBLRecordCustomersMonth"
    81. .Size = New System.Drawing.Size(150, 20)
    82. .Text = "im " & arrRecord(3)
    83. .Visible = True
    84. End With
    85. 'Controls auf die Form malen
    86. Me.Controls.Add(LBLLabelCustomers)
    87. Me.Controls.Add(LBLRecordCustomers)
    88. Me.Controls.Add(LBLRecordCustomersDate)
    89. yPosition += 50
    90. Dim Groupname As String
    91. 'Controls für jede Warengruppe erzeugen
    92. For i = 1 To GroupCount
    93. 'Name aus BindingSource lesen
    94. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(i - 1), DataRowView).Row, DtsSettings.ProductGroupRow)
    95. GroupName = ProductGroup.Name
    96. Dim strProductGroupRecord As String = GetMonthlyIncome(Groupname)
    97. 'LabelText in Variable speichern
    98. Dim arrProductGroupRecord() As String = strProductGroupRecord.Split("|")
    99. 'Label für Beschriftung
    100. Dim LBLLabel = New System.Windows.Forms.Label
    101. With LBLLabel
    102. .Location = New System.Drawing.Point(490, yPosition)
    103. .Font = New Font("Microsoft Sans Serif", 12)
    104. .TextAlign = ContentAlignment.MiddleRight
    105. .Name = "LBLLabelMonth " & Groupname
    106. .Size = New System.Drawing.Size(200, 20)
    107. .Text = GroupName
    108. .Visible = True
    109. End With
    110. 'Label für Rekord
    111. Dim LBLRecord = New System.Windows.Forms.Label
    112. With LBLRecord
    113. .Location = New System.Drawing.Point(700, yPosition)
    114. .Font = New Font("Microsoft Sans Serif", 12)
    115. .TextAlign = ContentAlignment.MiddleRight
    116. .Name = "LBLRecordMonth " & Groupname
    117. .Size = New System.Drawing.Size(120, 20)
    118. .Text = arrProductGroupRecord(0)
    119. .Visible = True
    120. End With
    121. 'Label für Rekord Datum
    122. Dim LBLRecordDate = New System.Windows.Forms.Label
    123. With LBLRecordDate
    124. .Location = New System.Drawing.Point(830, yPosition)
    125. .Font = New Font("Microsoft Sans Serif", 12)
    126. .TextAlign = ContentAlignment.MiddleLeft
    127. .Name = "LBLRecordMonth " & Groupname
    128. .Size = New System.Drawing.Size(150, 20)
    129. .Text = "im " & arrProductGroupRecord(1)
    130. .Visible = True
    131. End With
    132. 'Controls auf die Form malen
    133. Me.Controls.Add(LBLLabel)
    134. Me.Controls.Add(LBLRecord)
    135. Me.Controls.Add(LBLRecordDate)
    136. 'Position für nächste Controls anpassen
    137. yPosition += 30
    138. Next
    139. End Sub
    140. Private Function GetMonthlyIncomeAndCustomersRecord() As String
    141. 'Minimum und Maximum Jahr suchen
    142. Dim maxDate As Integer = Integer.Parse(DtsSettings.DailyIncome.Max(Function(x) x._Date).ToString("yyyy"))
    143. Dim minDate As Integer = Integer.Parse(DtsSettings.DailyIncome.Min(Function(x) x._Date).ToString("yyyy"))
    144. Dim _Date As Date
    145. Dim tempdate As Date
    146. Dim numberofdays As Integer
    147. Dim MonthlyIncome As Integer
    148. Dim MaxIncome As Integer
    149. Dim MonthlyCustomers As Integer
    150. Dim MaxCustomers As Integer
    151. Dim DateOfMaxIncome As Date
    152. Dim DateOfMaxCustomers As Date
    153. '1. Schleife für jedes Jahr
    154. For i = minDate To maxDate
    155. '2. Schleife für jeden Monat
    156. For j = 1 To 12
    157. 'Datum zusammenbauen
    158. _Date = Date.Parse("01." & j & "." & i)
    159. 'Anzahl der Tage für aktuellen Monat auslesen
    160. numberofdays = Integer.Parse(DateTime.DaysInMonth(i, j).ToString)
    161. '3. Schleife für jeden Tag des Monats
    162. For k = 0 To numberofdays - 1
    163. 'ausgewähltes Jahr
    164. tempdate = _Date.AddDays(k)
    165. 'Datum in den Einnahmen suchen
    166. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = tempdate)
    167. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    168. 'Einnahme zusammenrechnen
    169. MonthlyIncome += IncomeRow.DailyIncome
    170. 'Kunden zusammenrechnen
    171. MonthlyCustomers += IncomeRow.CustomerCount
    172. Next
    173. 'Wenn Monatsumsatz größer als Gesamtumsatz speichern der Daten
    174. If MonthlyIncome > MaxIncome Then
    175. MaxIncome = MonthlyIncome
    176. DateOfMaxIncome = Date.Parse("01." & j & "." & i)
    177. End If
    178. 'Wenn Monatskunden größer als Gesamtkunden speichern der Daten
    179. If MonthlyCustomers > MaxCustomers Then
    180. MaxCustomers = MonthlyCustomers
    181. DateOfMaxCustomers = Date.Parse("01." & j & "." & i)
    182. End If
    183. MonthlyIncome = 0
    184. MonthlyCustomers = 0
    185. Next
    186. Next
    187. Return (MaxIncome / 100).ToString("#,##0.00 €") & "|" & DateOfMaxIncome.ToString("MMMM yyyy") & "|" & MaxCustomers & "|" & DateOfMaxCustomers.ToString("MMMM yyyy")
    188. End Function
    189. 'Funktion zum auslesen der Monatsumsätze für jede Warengruppe
    190. Private Function GetMonthlyIncome(Groupname As String) As String
    191. 'Minimum und Maximum Jahr suchen
    192. Dim maxDate As Integer = Integer.Parse(DtsSettings.DailyIncome.Max(Function(x) x._Date).ToString("yyyy"))
    193. Dim minDate As Integer = Integer.Parse(DtsSettings.DailyIncome.Min(Function(x) x._Date).ToString("yyyy"))
    194. Dim _Date As Date
    195. Dim tempdate As Date
    196. Dim numberofdays As Integer
    197. Dim groupcount As Integer = DtsSettings.ProductGroup.Count
    198. Dim MonthlyIncome As Integer
    199. Dim MaxIncome As Integer
    200. Dim DateofMaxIncome As Date
    201. '1. Schleife für jedes Jahr
    202. For i = minDate To maxDate
    203. '2. Schleife für jeden Monat
    204. For j = 1 To 12
    205. 'Datum zusammenbauen
    206. _Date = Date.Parse("01." & j & "." & i)
    207. 'Anzahl der Tage für aktuellen Monat auslesen
    208. numberofdays = Integer.Parse(DateTime.DaysInMonth(i, j).ToString)
    209. '3. Schleife für jeden Tag des Monats
    210. For k = 0 To numberofdays - 1
    211. 'ausgewähltes Jahr
    212. tempdate = _Date.AddDays(k)
    213. 'Datum in den Einnahmen suchen
    214. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = tempdate)
    215. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    216. '4. Schleife für jede Warengruppe
    217. For L = 0 To groupcount - 1 'Schleife durch Product Group DataTable
    218. 'Name aus BindingSource lesen
    219. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(L), DataRowView).Row, DtsSettings.ProductGroupRow)
    220. If ProductGroup.Name = Groupname Then
    221. 'Warengruppenumsatz für Datum ermitteln und addieren
    222. Dim ProductGroupRow = DtsSettings.Distribution_Table.SingleOrDefault(Function(x) x.DailyIncomeRow._Date.Date = tempdate AndAlso x.ProductGroupRow.Name = groupname)
    223. If ProductGroupRow Is Nothing Then Continue For
    224. 'Umsätze addieren
    225. MonthlyIncome += ProductGroupRow.ProductGroupIncome
    226. End If
    227. Next
    228. Next
    229. If MonthlyIncome > MaxIncome Then
    230. MaxIncome = MonthlyIncome
    231. DateofMaxIncome = Date.Parse("01." & j & "." & i)
    232. End If
    233. MonthlyIncome = 0
    234. Next
    235. Next
    236. Return (MaxIncome / 100).ToString("#,##0.00 €") & "|" & DateofMaxIncome.ToString("MMMM yyyy")
    237. End Function


    Hier die Zusammenfassung, was angezeigt werden soll:
    • höchste Tageseinnahme (in Demo fertig)
    • Tag mit den meisten Kunden (in Demo fertig)
    • höchster Tagesumsatz für jede Warengruppe (wie höchste Tageseinnahme in Demo einbaubar - wenn mein Lösungsweg so ok ist)
    • höchste Monatseinnahme
    • Monat mit den meisten Kunden
    • höchster Monatsumsatz für jede Warengruppe
    • Monat mit höchstem pro Kopf Umsatz

    DerSmurf schrieb:

    Ich habe erstmal nur ein bisschen Code erstellt, um sicherzugehen, dass ich deine Vorgehensweise korrekt umgesetzt habe.

    Naja, halb:

    ErfinderDesRades schrieb:

    Ich würde die Rekorde beim Einlesen des Datasets ausrechnen und merken.
    Man kann innerhalb des Datasets ja zusätzlichen Code anlegen - auch Variablen, die die Rekorde merken.
    Bei dir sind die Variablen,die die Rekorde merken, aber wieder im Form.
    Wunderlich auch, dass deine DailyRecord-Variable vom Typ String ist.
    Es geht doch um (Geld)Beträge, also um Zahlen.
    Ah, sorry, falsch verstanden.
    Ich glaube dann habe ich es jetzt korrekt umgesetzt.

    ErfinderDesRades schrieb:

    Wunderlich auch, dass deine DailyRecord-Variable vom Typ String ist.

    Das liegt daran, dass ich nicht nur den Rekord an sich, sondern auch dessen Datum gespeichert habe: "235,36€|15.02.2013"
    Das habe ich nun in zwei Variablen des korrekten Typs geändert.

    Bitte schau mal über den Code in meinem DataSet, ob das so passt und ich brauche Hilfe bei der Umsetzung der Tagesrekorde für die Produktgruppen (der auskommentierte Code).
    Die Sub LoadDailyRecords in DtsSettings kann nicht auf ProductGroup.LoadDailyProductGroupRecords() zugreifen, weil nicht gefunden.
    Und die aufgerufene Sub an sich expoldiert dann vor Fehlern :(

    Hier erstmal der Code des DataSet, wenn ich deine Lösung immernoch nicht korrekt umgesetzt habe, brauchste die Demo ja garnicht erst runterladen.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Partial Class DtsSettings
    2. Public Sub LoadDailyRecords()
    3. DailyIncome.LoadDailyIncomeRecord()
    4. DailyIncome.LoadDailyCustomersRecord()
    5. 'ProductGroup.LoadDailyProductGroupRecords()
    6. End Sub
    7. Partial Public Class DailyIncomeDataTable
    8. Public Property DailyIncomeRecord As Double
    9. Public Property DailyIncomeRecordDate As Date
    10. Public Property DailyCustomersRecord As Integer
    11. Public Property DailyCustomersRecordDate As Date
    12. Public Sub LoadDailyCustomersRecord()
    13. Dim MaxCustomers = Me.Max(Function(x) x.CustomerCount)
    14. Dim TargetIncomeRowCust = Me.First(Function(x) x.CustomerCount = MaxCustomers)
    15. Dim CustomersDate As Date = TargetIncomeRowCust._Date
    16. DailyCustomersRecord = MaxCustomers
    17. DailyCustomersRecordDate = CustomersDate
    18. End Sub
    19. Public Sub LoadDailyIncomeRecord()
    20. 'Umsatz
    21. Dim MaxIncome = Me.Max(Function(x) x.DailyIncome)
    22. Dim TargetIncomeRow = Me.First(Function(x) x.DailyIncome = MaxIncome)
    23. Dim IncomeDate As Date = TargetIncomeRow._Date
    24. DailyIncomeRecord = (MaxIncome / 100)
    25. DailyIncomeRecordDate = IncomeDate
    26. End Sub
    27. End Class
    28. Partial Public Class ProductGroupRow
    29. Public Property DailyProductGroupRecord() As Double
    30. Public Property DailyProductGroupRecordDate() As Date
    31. Public Function GetIncomeRecord() As String
    32. Dim MaxValue = Me.GetDistribution_TableRows.Max(Function(x) x.ProductGroupIncome)
    33. Dim TargetDistributionRow = Me.GetDistribution_TableRows.First(Function(x) x.ProductGroupIncome = MaxValue)
    34. Return ((MaxValue / 100).ToString("##,##0.00") & "|" & TargetDistributionRow.DailyIncomeRow._Date.ToShortDateString)
    35. End Function
    36. 'Public Sub LoadDailyProductGroupRecords()
    37. ' Dim GroupCount As Integer
    38. ' 'GroupCount = ProductGroup.Count
    39. ' GroupCount = 8
    40. ' ReDim DailyProductGroupRecord(0 To GroupCount - 1)
    41. ' Dim Groupname As String
    42. ' For i = 0 To GroupCount - 1
    43. ' 'Name aus BindingSource lesen
    44. ' Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(i), DataRowView).Row, DtsSettings.ProductGroupRow)
    45. ' Groupname = ProductGroup.Name
    46. ' DailyProductGroupRecord(i) = Groupname & "|" & GetIncomeRecord()
    47. ' Next
    48. 'End Sub
    49. End Class
    50. End Class
    Dateien
    Jo, so prinzipiell habichs so gemeint.
    Nur wo ich angucke, scheint mir, was du an Rekorden speichern willst sind doch DailyIncome-Datensätze - dann speicher die doch auch (anstatt nur zweier ihrer Properties in je eine Variable).
    Also sowas:

    VB.NET-Quellcode

    1. Partial Class DtsSettings
    2. Partial Public Class DailyIncomeDataTable
    3. Public Property IncomeRecord As DailyIncomeRow
    4. Public Property CustomersRecord As DailyIncomeRow
    Dann haste zwei Variablen gespart, und ausserdem Rekord-Datum und Rekord-Wert sinnig zusammengefasst - nämlich garnet erst auseinandergepflückt.
    Wobei Benamung: Auf Englisch bedeutet "Record" glaub "Datensatz". Was "Rekord" auf englisch heisst weiss ich nicht.
    Ich hab jetzt einen Dataset-Ordner gebastelt, und eine zusätzlcihe Dataset-Datei, weil das jetzt Business-Logik ist, und finde ich nicht gut, wenn solch im SolutionExplorer wie versteckt ist.
    Dataset-Businesslogik gehört zusammen zum designeten Dataset, ist aber etwas anderes (und kann noch deutlich anwachsen) - daher es in zwei erkennbar getrennte Files aufteilen, und beide zusammen in einen Ordner - schaus dir mal an.
    Weiters hab ich eine Version meiner Helpers zugefügt, weil ich eine meiner Linq-Erweiterungen benötigte.
    Weil Standard-Linq ist unzureichend, wenn Maximum/Minimum-Datensätze gesucht werden.
    Linq kann zwar ein Maximum auffinden in einer Datensatz-Menge, aber das ist dann nur eine dumme Zahl, und ist nicht der gesuchte Datensatz mit der Property, die den Wert aufweist.
    Jo, mit meiner fabelhaften MaxBy-Extension kann ich deine Rekorde-Suche ziemlich schnucklig abfackeln:

    VB.NET-Quellcode

    1. Partial Class DtsSettings
    2. Public IncomeRecord As DailyIncomeRow
    3. Public CustomersRecord As DailyIncomeRow
    4. Public ReadOnly ProductGroupRecords As New List(Of Distribution_TableRow)
    5. Public Sub LoadDailyRecords()
    6. IncomeRecord = DailyIncome.MaxBy(Function(x) x.DailyIncome)
    7. CustomersRecord = DailyIncome.MaxBy(Function(x) x.CustomerCount)
    8. Dim rekorde = From dist In Distribution_Table Group By dist.ProductGroupID Into rekord = MaxBy(dist.DailyIncomeRow.DailyIncome) Select rekord
    9. ProductGroupRecords.Clear() : ProductGroupRecords.AddRange(rekorde)
    10. End Sub
    11. End Class
    Du siehst - die Rekorde sind jetzt Rekord-Datensätze, nicht mehr nur die Rekord-Werte.
    Ausserdem hab ich alle Rekorde in die Dataset-Klasse verfrachtet - also aus der DailyIncome-Tabelle rausgenommen, und aus der ProductRow-Klasse ebenfalls.
    Die Rekorde nach Gruppen sind nun DistributionsRows, nämlich Zuordnungs-Datensätze, die auf beides verweisen: Auf die Rekord-DailyIncomeRow und auf die ProductGroupRow, für die das ein Income-Rekord ist.

    Tatsächlich hätte man die Anlage der Rekorde auch so belassen können, wie du sie angelegt hast - in der DailyIncomeTable bzw. in den ProductGroupRows - wär sogar stärker objektorientiert.

    Ist eine Gewohnheit von mir, da die Objektorientierung meist nicht so weit zu treiben.
    Irgendwie isses bei meiner Version näher beieinander - nämlich alle Rekorde gleich welcher Art, und auch die Methode, die den Kram ausrechnet, stehen beieinander.
    Bei deiner strengeren Objektorientierung ist das auf mehrere Klassen verteilt und wird dadurch unübersichtlicher.
    Aber wie gesagt: das geht in Richtung Geschmackssache, bzw. kann von Fall zu Fall anders sein. Etwa wenn die BL an Umfang zunimmt, und dadurch wieder unüberichtlich wird, isses ja naheliegend, die BL weiter in die Klassen zu verteilen, und je Klasse eine Datei anlegen - OOP-Ordnung eben.



    Achso - ich hab auch noch unnütze Bibliotheken rausgeworfen, sowie ein paar GeneralImporte
    Dateien

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

    Das ist Mega!
    Den Code in die Klasse DtsSettings zu stopfen finde ich auch übersichtlicher, weils ja eine übersichtliche Menge Code ist.
    Was ich von diesem Ordner für das DataSet halten soll, weiß ich nicht - aber wenn man das so macht, mach ich das halt auch so.

    Ich wollte schnell die Warengruppenrekorde in die Form malen - aber ich muss das Niveau dieses Threads leider etwas senken...
    Nach meinem Verständniss vom DataSet ist die Distribution_Table der Parent von DailyIncome und auch der Parent von ProductGroup.
    Wenn ich also Umsatz und Datum, die zur ProductGroupRow aus DtsSettings gehören - Public ReadOnly ProductGroupRecords As New List(Of Distribution_TableRow) - finden will, dann
    suche ich mir die ParentRow (Distribution_Table) - da steckt der Umsatz.
    Wenn ich diese habe suche ich mir hierzu die gehörige DailyIncomeRow - da steckt das Datum drin.
    Klappt aber nicht...
    Ich komme nicht von ProductGroupRecord zur Distribution_Table, sondern direkt zu DailyIncome - DailyIncome muss also der Parent sein. Aber das begreife ich nicht...

    VB.NET-Quellcode

    1. Dim ProductGroupCounter = -1
    2. For Each row In DtsSettings.ProductGroup
    3. ProductGroupCounter += 1
    4. Dim LBLLabelProductGroup = CreateLabel(5, yPosition, New Size(200, 20), "LBLLabelProductGroup", row.Name)
    5. Dim ProductGroupRecord = DtsSettings.ProductGroupRecords(ProductGroupCounter)
    6. Dim DailyIncomeRow = ProductGroupRecord.DailyIncomeRow 'so bekomme ich die ParentRow - aber DailyIncome und ProductGroup sind doch nicht direkt, sondern über die Distribution_Table, verbunden.
    7. Dim RecordDate = DailyIncomeRow._Date
    8. Dim DistributionTableRow = DailyIncomeRow.GetDistribution_TableRows
    9. 'jetzt hab ich doch ganz viele Distribution Table Rows.
    10. 'aber ich will doch nur die eine Parentrow zu meiner ProductGroupRow...
    11. 'Dim DistTableRow = ProductGroupRecord.Distribution_Tablerow
    12. Dim LBLRecordProductGroup = CreateLabel(210, yPosition, New Size(120, 20), "LBLRecordProductGroup", "Rekord")
    13. Dim LBLRecordProductGroupDate = CreateLabel(340, yPosition, New Size(150, 20), "LBLRecordProductGroupDate", RecordDate.ToShortDateString)
    14. yPosition += 30
    15. 'Controls auf die Form malen
    16. Me.Controls.Add(LBLLabelProductGroup)
    17. Me.Controls.Add(LBLRecordProductGroup)
    18. Me.Controls.Add(LBLRecordProductGroupDate)
    19. Next

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

    DerSmurf schrieb:

    Was ich von diesem Ordner für das DataSet halten soll, weiß ich nicht - aber wenn man das so macht, mach ich das halt auch so.
    Dass "man" das so macht wäre übertrieben.
    Was man sagen kann "man macht" ist, dass man Businesslogik von Anzeige-Logik zu trennen versucht.
    Also im Form Code zu haben, der iwelche Dataset-Tabellen durchsucht ist nicht sexy.
    Solchen Code - Businesslogik - lagert man aus, und da gibts viele Möglichkeiten.
    Ich finde meine Variante, die Businesslogik dann eben im Dataset anzulegen - da sie ja nicht ins Form gehört, besonders plausibel. Aber man kanns auch anders machen. Es ist sogar die Mehrheit die's anders macht, denn das typisierte Dataset ist den allermeisten Programmierern unbekannt.
    Man kann die Businesslogik auch im Dataset versteckt lassen, dann sieht man sie nur bei Rechtsklick aufs Dataset, und "Code anzeigen". Aber Businesslogik ist total wichtig und ist imo eine sehr schlechte Idee, die dergestalt zu verstecken, dass sie nur per KontextMenü sichtbar wird.
    Damit hast du also zwei Dateien im SolutionExplorer, und beide sind das Dataset - eben als partiale Klassen. Das habe ich durch den ähnlichen Datei-Namen kenntlich gemacht, dass die so eng zusammen gehören, und ausserdem durch den Ordner, wo beide eben drinne sind.
    Im Fortschritt deines Projekt kann die BL auch noch gewaltig wachsen.
    Wenn Ich Businesslogik in DataTables anlege (wie du's anfangs hattest - ist ja oft sehr sinnvoll), dann lege ich dafür oft weitere BL-Dateien an. Etwa eine DtsSettings.ProductGroup.vb käme bei raus, wenn ich inne ProductGroup Businesslogik von mehr als 20 Zeilen anzusiedeln hätte.
    Dann hätten wir schon drei Dateien in dem Ordner - die alle dasselbe Dataset sind (partiale Klasse).

    Also das ist auch was, was "man" macht: Man macht Zusammengehörigkeit von Dingen kenntlich, und möglichst leicht auffindbar.
    Und wieder gibts dafür viele Mittel - in diesem Falle wende ich zwei Mittel an, nämlich die ähnliche Benamung der Dateien, und dass ich sie in denselben Ordner stopfe.
    Und wieder machts die Mehrheit anders, denn auch partiale Klassen sind den meisten Programmierern kaum bekannt, sodass sie dieses Feature nicht aktiv zur Programm-Strukturierung nutzen.



    DerSmurf schrieb:

    Nach meinem Verständniss vom DataSet ist die Distribution_Table der Parent von DailyIncome und auch der Parent von ProductGroup.
    nein - Distribution_Table ist den beiden anderen Tabellen untergeordnet - nicht über.
    Das kannste direkt nachgucken im Dataset-Designer per Doppelklick auf die Relationen - da ist angegeben, was Parent- und was Child-Table ist.

    Dein Code versucht iwie was anneres, als wie ich ProductGroupRecords gedacht hab.
    Die Rekorde habe ich doch als Public ReadOnly ProductGroupRecords As List(Of Distribution_TableRow) bereitgestellt - die musst du durchschleifen - nicht die DtsSettings.ProductGroup.
    Und jeder dieser Rekord-Datensätze - es sind ja Distribution_TableRows - hat eine Verbindung zu einer DailyIncomeRow, wo du das RekordIncome und das Datum abrufen kannst,
    und eine Verbindung zu einer ProductGroupRow, wo du den Namen der ProductGroup abrufen kannst.

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

    Au ja, das sind ja Distribution_Tablerows...
    Das die anderen beiden Tables Parents hiervon sind hätte ich ja auch im Datenquellenfenster sehen können.
    Dort ist ja in DailyIncome und ProductGroup jeweils eine Distribution_Table eingeschachtelt...

    Ich bin mir jetzt sicher, dass mein Code korrekt ist. Ist er aber nicht ...
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Controls für jede Warengruppe erzeugen
    2. For Each record In DtsSettings.ProductGroupRecords
    3. 'Daten aus DataSet sammeln
    4. 'erst die beiden ParentRows in ProductGroup und DailyIncome zu "record" suchen
    5. Dim ParentProductGroupRow = record.ProductGroupRow
    6. Dim ParentDailyIncomeRow = record.DailyIncomeRow
    7. 'die Daten aus den ParentRows lesen
    8. Dim RecordDate = ParentDailyIncomeRow._Date
    9. Dim ProductGroupName = ParentProductGroupRow.Name
    10. Dim ProductGroupIncome = record.ProductGroupIncome / 100
    11. 'Controls generieren
    12. Dim LBLLabelProductGroup = CreateLabel(5, yPosition, New Size(200, 20), "LBLLabelProductGroup", ProductGroupName)
    13. Dim LBLRecordProductGroup = CreateLabel(210, yPosition, New Size(120, 20), "LBLRecordProductGroup", ProductGroupIncome.ToString("#,##0.00"))
    14. Dim LBLRecordProductGroupDate = CreateLabel(340, yPosition, New Size(150, 20), "LBLRecordProductGroupDate", RecordDate.ToShortDateString)
    15. 'Controls auf die Form malen
    16. Me.Controls.Add(LBLLabelProductGroup)
    17. Me.Controls.Add(LBLRecordProductGroup)
    18. Me.Controls.Add(LBLRecordProductGroupDate)
    19. yPosition += 30
    20. Next

    Es werden die Namen der ProductGroups (Variable ProductGroupName) korrekt angezeigt. Der Umsatz und das Datum jedoch nicht.
    RecordDate entspricht immer dem Datum der höchsten Tageseinnahme (DailyIncome.DailyIncome) - dementsprechend ist auch die ParentDailyIncomeRow.
    ProductGroupIncome ist immer 0, außer wenn der höchste Umsatz in der entsprechenden Kategorie am gleichen Datum wie die höchste Tageseinnahme stattfindet...

    Was hab ich nun schon wieder verafft?
    nee - ich glaub, meine Maximum-Suche ist fehlerhaft, es muss glaub heissen:

    VB.NET-Quellcode

    1. 'Dim rekorde = From dist In Distribution_Table Group By dist.ProductGroupID Into rekord = MaxBy(dist.DailyIncomeRow.DailyIncome) Select rekord
    2. Dim rekorde = From dist In Distribution_Table Group By dist.ProductGroupID Into rekord = MaxBy(dist.ProductGroupIncome) Select rekord
    Weil das Maximum der ProductGroupIncome-Werte wird ja gesucht, nicht dass der verknüpften DailyIncomes.
    Glaub ich jedenfalls - ist nämlich auch ungetestet.
    Hallo lieber @ErfinderDesRades Du glaubst richtig. Mit der oben gezeigten Änderung klappts einwandfrei.
    Also läuft nun die Anzeige der Tagesrekorde korrekt und vor allem schnell durch.
    Dann würde ich gerne meine Fragen und Anmerkungen (die ich mir aufgespart habe, damit nicht soviel gleichzeitig passiert) loswerden.

    1. In der DtsSettings Klasse sind die drei Properties, welche die entsprechenden DataRows halten hinzugekommen:

    VB.NET-Quellcode

    1. Public IncomeRecord As DailyIncomeRow
    2. Public CustomersRecord As DailyIncomeRow
    3. Public ReadOnly ProductGroupRecords As New List(Of Distribution_TableRow)

    Die List Of hast du ReadOnly deklariert, IncomeRecord und CustomersRecord nicht, obwohl hier ja eigentlich (erstmal) ein "nurLeseZugriff" auch reicht. Warum?

    2.

    ErfinderDesRades schrieb:

    Wobei Benamung: Auf Englisch bedeutet "Record" glaub "Datensatz". Was "Rekord" auf englisch heisst weiss ich nicht.

    Ich bin mir auch sicher, dass "record" etwas wie Datensatz oder Eintrage heißt und eben nicht Rekord. Aber wenn ich nach Umsatzrekord englisch google, scheint es record sei korrekt.
    Aber letzlich ist ja wichtig, dass sich jeder anhand des Variablennamens vorstellen können muss, was diese tut - da taugt record ja allemal.

    3.

    ErfinderDesRades schrieb:

    Weiters hab ich eine Version meiner Helpers zugefügt

    Ich habe an meinem Huaptprogramm ohnehin die SmalEd der Helpers dranne und nutze hiervon bisher nur EditNew und EditCurrent, also perfekt. (und dann hab ich mal eine neuere Version :o)

    4.

    ErfinderDesRades schrieb:

    Dataset-Businesslogik gehört zusammen zum designeten Dataset, ist aber etwas anderes (und kann noch deutlich anwachsen) - daher es in zwei erkennbar getrennte Files aufteilen, und beide zusammen in einen Ordner

    Ich nehme an das hat nur Einfluss auf das fertige Programm? - Also das was nach Projekt erstellen entsteht?
    Dann macht es ja Sinn zusammengehöriges in eigene Unterordner zusammenzuschmeißen. Denn ich suche in meinem Hauptprogramm bei den ganzen Forms (alle im Hauptordner) schonmal öfters...

    5.

    ErfinderDesRades schrieb:

    Es ist sogar die Mehrheit die's anders macht, denn das typisierte Dataset ist den allermeisten Programmierern unbekannt.

    Warum ist das so? Das typisierte DataSet hat doch im Vergleich zum untypisierten eigentlich nur Vorteile?

    6. Ich nehme an das Kürzel BL steht für BusinessLogik? Und meint BusinessLogik Code der "rechnet" und "Daten sucht"? Also (fast) alles an Code, der nicht zur Anzeige dient`?
    Im konkreten Beispiel hier wäre also das Zusammensuchen der Rekorde im DataSet Businesslogik, das Anzeigen dieser Daten dann nicht?
    Und eben diese Businesslogik möchte ich (der Übersichtlichkeit halber) nicht in der Anzeigeform haben?

    DerSmurf schrieb:


    1. In der DtsSettings Klasse sind die drei Properties, welche die entsprechenden DataRows halten hinzugekommen:

    VB.NET-Quellcode

    1. Public IncomeRecord As DailyIncomeRow
    2. Public CustomersRecord As DailyIncomeRow
    3. Public ReadOnly ProductGroupRecords As New List(Of Distribution_TableRow)

    Die List Of hast du ReadOnly deklariert, IncomeRecord und CustomersRecord nicht, obwohl hier ja eigentlich (erstmal) ein "nurLeseZugriff" auch reicht. Warum?
    Readonly bewirkt, dass man die Variable nur bei der Deklaration beschreiben kann, oder spätestens im Konstruktor (= Sub New). Das scheidet für IncomeRecord und CustomersRecord ja aus, die können ja erst später berechnet werden, wenn Daten geladen sind.
    Möglicherweise werden Daten ja auch mal neu geladen, also müssen diese Variablen auch mehrmals beschreibbar sein.
    Aber die List(Of Distribution_TableRow) soll immer dieselbe bleiben.
    Werden GroupRekorde berechnet, dann muss man die Liste nicht austauschen, sondern die Liste bleibt dieselbe, sie wird nur gelöscht und neu befüllt.
    IncomeRecord und CustomersRecord sind ganz anfangs auch Nothing - die Liste hingegen ist gleich ein gültiges Objekt: eine leere Liste nämlich.

    DerSmurf schrieb:

    4.

    ErfinderDesRades schrieb:

    Dataset-Businesslogik gehört zusammen zum designeten Dataset, ist aber etwas anderes (und kann noch deutlich anwachsen) - daher es in zwei erkennbar getrennte Files aufteilen, und beide zusammen in einen Ordner

    Ich nehme an das hat nur Einfluss auf das fertige Programm? - Also das was nach Projekt erstellen entsteht?
    Dann macht es ja Sinn zusammengehöriges in eigene Unterordner zusammenzuschmeißen. Denn ich suche in meinem Hauptprogramm bei den ganzen Forms (alle im Hauptordner) schonmal öfters...
    Wie du Ordner in deiner Solution einrichtest, und welche Dateien drinne sind ist ganz deine Sache.
    Wenn du viele Forms hast ists sicher nützlich, die in einen Ordner "GUI" zu tun.
    Man kann auch weiter strukturieren, etwa in Dialoge, Forms, UserControls unterteilen.
    Bei mir gibts meist ein Mainform, ausserhalb aller Ordner. Darauf hab ich meist ein TabControl, und auf jedem Tab ein UserControl - die UserControls finden sich in einem Ordner "Ucl". Und dann habich noch Dialoge - "Dialogs".
    Mehrere Forms habich meist nicht - ein MainForm mit Tabs ist mein bevorzugtes Anwendungs-Design.

    DerSmurf schrieb:

    5.

    ErfinderDesRades schrieb:

    Es ist sogar die Mehrheit die's anders macht, denn das typisierte Dataset ist den allermeisten Programmierern unbekannt.

    Warum ist das so? Das typisierte DataSet hat doch im Vergleich zum untypisierten eigentlich nur Vorteile?
    Ja, finde ich auch.
    Aber man muss den Kram erstmal lernen, inklusive, es zu vermeiden, in untypisierten Code-Stil zurückzufallen.
    Das ist für jmd, ders nicht anders kennt als untypisiert, quasi ausserhalb des sichtbaren Bereichs.
    Und Microsoft publiziert nur Vorgehensweisen mit EF - Dataset würden die glaub am liebsten wieder abschaffen.

    DerSmurf schrieb:

    6. Ich nehme an das Kürzel BL steht für BusinessLogik? Und meint BusinessLogik Code der "rechnet" und "Daten sucht"? Also (fast) alles an Code, der nicht zur Anzeige dient`?
    Im konkreten Beispiel hier wäre also das Zusammensuchen der Rekorde im DataSet Businesslogik, das Anzeigen dieser Daten dann nicht?
    Und eben diese Businesslogik möchte ich (der Übersichtlichkeit halber) nicht in der Anzeigeform haben?
    Ja genau.
    Danke!
    Wenn du noch Geduld mit mir hast, würde ich mich dann gerne an die Monatsrekorde machen.
    Meinen (funktionierenden) Versuch habe ich im Demoprojekt - auskommentiert - eingefügt.
    Dieser Funktioniert ist aber von der Logik her schlecht und viel zu langsam.
    Man sieht aber das Ziel der Ausgabe, nämlich
    • Monat mit höchstem Gesamtumsatz (Umsatz und Monat - also Datum)
    • Monat mit den meisten Kunden
    • Monate mit den höchsten Einnahmen für alle Warengruppen
    • außerdem hätte ich gerne noch eine neue Funktion - den Monat mit höchstem pro Kopf Umsatz
    Also quasi das gleiche, wie jetzt fertiggestellt für die Tage, nur eben für die Monate.

    Meine rangehensweise wäre folgende:
    In DailyIncome._Date den kleinsten und höchsten Wert suchen.
    Dann die gleiche Logik anwenden, wie dein Code zur Anzeige der Jahresauswertung.
    Also jeweils die Monate durchgehen welche zwischen DtsSettings.DailyIncome._Date Min und Max liegen.
    Hier errechne ich mir dann die entsprechenden Werte und speichere diese (also Monatsumsatz z.B. MonthlIyncome as double).
    Das mache ich mit allen Monaten und schaue jeweils ob MonthlyIncome größer ist. Fertig.

    Haut das (zumindest von der Logik) so hin, oder wäre eine andere herangehensweise besser? d.h. schneller?
    Ich weiss nicht genau, welchen Code du meinst.
    Wenn ich einen Code von dir überarbeiten soll, dann stell doch eine Version ein, die den unüberarbeiteten Code ohne viel schnickschnack-klickklick aufruft, und das Ergebnis auch anzeigt, vor allem, wenns schoma richtig ist.
    Dann kann ich gleich mit überarbeiten anfangen, und muss nicht zuvor erstnoch alle möglichen Vorraussetzungen schaffen - die auch noch fehlerhaft sein können.
    Das mache ich doch glatt.
    Den zu überarbeitenden Code findest du in rework.vb.
    Die Startsub dieser Datansuch Odysee wird im Form Load Event aufgerufen.
    Du brauchst also nur den Play Button drücken und los gehts.
    Jedoch muss ich dich an dieser Stelle warnen, drück lieber nicht auf Play, sonst gibts graue Haare. Die Ausführung dauert gute 40 Sekunden. Ich habe dir daher ein Bild angehangen, wies aussieht, wenn man sich das Starten des Programmes antut. Die Linke Seite ("Tagesrekorde") ist in Ordnung - die rechte Seite ("Monatsrekorde") ist die, welche so lange braucht.

    ErfinderDesRades schrieb:

    Ich weiss nicht genau, welchen Code du meinst.

    Diesen schreibe ich mal hier unterm Spoiler, denn ich würde ihn brauchen (denn mir fällt keine effizientere Methode ein, das DataSet zu durchforsten) - falls du ihn brauchst und das entsprechende Demo Programm nicht mehr hast.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Sub zum auslesen der Einnahmen für ein Jahr
    2. Private Sub GetDataSummaries(year As Integer, ArrIncome(,) As Double, customersPerMonth() As Integer)
    3. Dim dt0 = New Date(year, 1, 1), dt1 = dt0.AddYears(1) ' Zeit-Bereich
    4. Dim productGroups = DtsSettings.ProductGroup.ToArray
    5. Dim groupcount = productGroups.Length
    6. Dim distributionTables = From distTbl In productGroups.SelectMany(Function(x) x.GetDistribution_TableRows)
    7. Let dt = distTbl.DailyIncomeRow._Date
    8. Where dt >= dt0 AndAlso dt < dt1 Select distTbl
    9. For Each rwDistrTbl In distributionTables
    10. Dim rwPG = rwDistrTbl.ProductGroupRow
    11. Dim month = rwDistrTbl.DailyIncomeRow._Date.Month
    12. Dim iProdGroup = Array.IndexOf(productGroups, rwPG)
    13. ArrIncome(month - 1, iProdGroup) += CDbl(rwDistrTbl.ProductGroupIncome / 100)
    14. ArrIncome(12, iProdGroup) += CDbl(rwDistrTbl.ProductGroupIncome / 100)
    15. Next
    16. 'IncomeRows auswerten
    17. For Each rwIncome In DtsSettings.DailyIncome.Where(Function(x) x._Date >= dt0 AndAlso x._Date < dt1)
    18. customersPerMonth(rwIncome._Date.Month - 1) += rwIncome.CustomerCount 'monatliche Kunden aufsummieren
    19. Next
    20. For Monat = 0 To 12 ' Jahres-Income bilden: je ProductGroup, aber auch "gesamt"
    21. For iProdGroup = 0 To groupcount - 1
    22. ArrIncome(Monat, groupcount) += ArrIncome(Monat, iProdGroup) 'monatliches Income je ProductGroup in die letzte Spalte("gesamt") aufsummieren
    23. Next
    24. Next
    25. End Sub
    Bilder
    • Unbenannt.jpg

      371,32 kB, 1.920×1.080, 29 mal angesehen
    Dateien
    Jo, das ist schon bisserl knifflig.
    Weil man muss die DistributionTableRows (was für ein abscheulicher Name!) erstmal nach Kategorien gruppieren.
    Dann die einzelnen Kategorien-Gruppen nochmal nach Monaten gruppieren.
    Und von den MonatsGruppen die Summen bilden.
    Und von den Summen der Monatsgruppen die mit der maximalen Summe finden.
    Und diese gefundenen Daten in ein Tuple stopfen, mit Monat, Kategorie und Summe.

    Es gibt im Dataset.BL nun eine weitere Rekord-Liste - die Deklarationen sehen also nun so aus:

    VB.NET-Quellcode

    1. Partial Class DtsSettings
    2. Public IncomeRecord As DailyIncomeRow
    3. Public CustomersRecord As DailyIncomeRow
    4. Public ReadOnly ProductGroupRecords As New List(Of Distribution_TableRow)
    5. Public ReadOnly MonthlyGroupRecords As New List(Of Tuple(Of Date, ProductGroupRow, Integer))
    Dateien
    Also das Ergebnis ist Mega! Aus über 40 Sekunden ist nichtmal eine geworden!

    Ich habe erstmal zwei Fragen zur Ausgabe der Daten.
    1. In der rework.vb steht zu oberst #If True Then dann die Subs CreateTwoLabelRowsForWhatever und WriteMonthlyRecords dann #ElseIf True Then, dann wieder die Sub WriteMonthlyRecords - aber mit anderem Inhalt, gefolgt von '#ElseIf True Then #End If
    Wenn ich hier alles auskommentiere außer den ersten If True Zweig, läuft der Code genauso.
    Wofür ist das gut?

    2. Warum trennst du die Anzeige von gesamt Monatsrekord und gesamt Kunden, von denen für die einzelnen Warengruppen?
    Und warum nennst du die Erstellung der gesamt Monatsrekorde und Kunden CreateTwoLabelRowsForWhatever?

    3. Du nutzt nicht die Sub CreateLabel, weil du meinen Anzeigecode kopiert hast? Aber das sollte ich noch ändern?

    4. Kannst du mir einen passenden Namen für die DistributionTable nennen? Denn sie ist ja irgendwie die "Schnittstelle" zwischen DailyIncome und ProductGroup und "verteilt" quasi die Daten.

    5. Die Sub GetMonthlyIncome, welche bisher den Umsatz der Warengruppen gesucht hat ist hinfällig. Die neue Suche hast du in DtsSettings geschupst.
    Die Funktion GetMonthlyIncomeAndCustomersRecord - welche den höchsten gesamtUmsatz, sowie den Monat mit den meisten Kunden sucht ist unverändert.
    Diese muss doch auch in DtsSettings und die maxDaten in einer Property gespeichert werden, oder nicht?

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

    Zunächstmal: Die Gruppiererei geht noch ein bischen einfacher, denn die erste Gruppierung - die nach Kategorien - stellt das Dataset ja bereit - man kann von jeder ProductGroup ja die Distri-Dinger abrufen.
    Dann wird die Methode so:

    VB.NET-Quellcode

    1. Private Sub CalculateMonthlyGroupRecords()
    2. Me.MonthlyGroupRecords.Clear()
    3. For Each rwProdGroup In Me.ProductGroup
    4. Dim monthInfos = Aggregate dist In rwProdGroup.GetDistribution_TableRows
    5. Let dt = dist.DailyIncomeRow._Date, dtMonth = New Date(dt.Year, dt.Month, 1)
    6. Group By dtMonth Into prodGrIncome = [Select](dist.ProductGroupIncome).
    7. Select dtMonth, monthSum = prodGrIncome.Sum Into ToArray
    8. Dim maxMonthPerKategorie = monthInfos.MaxBy(Function(x) x.monthSum)
    9. MonthlyGroupRecords.Add(Tuple.Create(maxMonthPerKategorie.dtMonth, rwProdGroup, maxMonthPerKategorie.monthSum))
    10. Next
    11. End Sub

    Das nur nebenbei




    zu 1.
    Das mit dem #If True ist ein Trick von mir, um Blockweises Auskommentieren zu ermöglichen.
    Von dieser #If True - #ElseIf True - Kette wird ja nur der erste Block kompiliert.
    so hab ich mehrere Varianten, und immer die oberste ist aktiv.
    Ich kann auch im Editor mit der Maus einen anderen Block nach oben verschieben und so aktivieren.
    Braucht man nur zum Entwickeln - habich vergessen zu löschen.

    Zu 2.
    Ich musste die Label-Creation der Monatsgruppen neu machen - das andere nicht.
    Das andere hab ich auch garnet kapiert, und interessierte mich nicht - daher habichs in eine Methode gepackt, mit der ich mich nicht weiter auseinandersetzen musste.
    Was ist das "Summe der Monatsrekorde"? - wird da wirklich der Monatsrekord von Kategorie1 - welcher vlt. aus Juni 2012 stammt mit dem Monatsrekord von Kategorie2- zB aus Dezember 2018 zusammengerechnet?
    Was bringt das?

    Zu 3.
    Mit deine Label-Createrei will ich nix zu tun haben.
    In meiner Welt sind diese Daten Tabellen, und gehören in einem Datagridview angezeigt.
    Dynamisches Erzeugen von Controls führt ganz schnell in Sackgassen.
    Etwa wenn Daten sich ändern muss man die entsprechenden Controls wieder-suchen um was neues reinzumachen.
    Oder man muss alle Controls wieder runterschmeissen und erneut wieder hinmachen.
    Und sortieren, editieren kann man sowas nicht.
    usw.

    zu 4.
    Hmm - schwierig.
    Ich glaub ich würde deutsch benamen.
    ProductGroup -> Kategorie
    DailyIncome -> Tag
    Distribution_Table -> TagesUmsatz

    Oder vielleicht auch nur Umsatz, denn dass es der Tages-Umsatz einer Kategorie ist, erschliesst sich aus den ForeignKeys: Einer geht auf Tag, der andere auf Kategorie.
    Aber so Umbenennerei ist äusserst heikel.
    Normal hilft der Background-Compiler ja, Codenamen umzunennen. Aber bei generiertem Dataset-Code kanner das nicht.
    Tatsächlich fährt man am besten mit projektweiter Volltext-Ersetzung.
    Aber schwierig - daher Backup machen, weil bestimmt mehrere Versuche nötig sein werden.

    zu 5.
    Jo - korrekt.
    Du siehst: BusinessLogik hat einiges Wachstumspotential

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

    2.
    Die SUB createtwolabelrowsforwhatever sucht den gesamt Monatsrekord und den Kundenrekord, nicht die Summe der Monatsrekorde.
    Also es werden natürlich nicht die Einnahmen jedes Warengruppenrekordes addiert.
    So wie es einen Tag mit höchsten Umsatz gibt, gibt es auch einen Monat mit höchsten Umsatz.
    Also im Juli nehme ich 100 ein, im August 80, dann ist Juli der Rekordmonat.
    Mit den Kunden das gleiche.
    Diese Daten sucht die sub.
    Diese müsste ja ebenfalls neu, denn die Werte brauche ich ja als Properties in DtsSettings.
    Und wenn der Code so geschrieben ist, dass du nicht weißt was da passiert, wenn du den Code anguckst, dann muss sie glaube ich dringend neu xD
    Siehe 5.

    4.
    Sollte ich dann auch die Spalte DailyIncome.Date umbenennen?
    Denn Date ist ja bereits von VB belegt, muss ich ja mit _date ansprechen.

    Könntest du bei der oben geposteten Sub CalculateMonthlyGroupRecords Kommentare einfügen?
    Ich verstehe da in vielen Zeilen echt nur Bahnhof

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

    DerSmurf schrieb:

    Denn Date ist ja bereits von VB belegt, muss ich ja mit _date ansprechen.
    Obwohl ich normalerweise grundsätzlich englische Namensgebung verwende, benutze ich bei Date aus diesen Gründen öfters den lateinischen Begriff ​Datum.
    Das verstehen auch Nicht-Deutsche. Und Deutsche sowieso.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --