Существует множество проблем с этим кодом, но для решения вашей конкретной проблемы c вы должны начать с того, что в вашем DataSet
есть DataRelation
между двумя DataTables
. Затем вы можете сразу получить все дочерние строки для любой родительской строки и родительскую строку для любой дочерней строки. В качестве общего примера вы можете создать такой DataSet
, например:
Dim data As New DataSet
Dim parentTable = data.Tables.Add("Parent")
Dim childTable = data.Tables.Add("Child")
With parentTable.Columns
parentTable.PrimaryKey = {.Add("ParentId", GetType(Integer))}
.Add("ParentName", GetType(String))
End With
With childTable.Columns
childTable.PrimaryKey = {.Add("ChildId", GetType(Integer))}
.Add("ParentId", GetType(Integer))
.Add("ChildName", GetType(String))
End With
data.Relations.Add("ParentChild",
parentTable.Columns("ParentId"),
childTable.Columns("ParentId"))
Затем вы можете получить доступ к дочерним строкам, указав c для каждой родительской строки, например:
For Each parentRow As DataRow In parentTable.Rows
For Each childRow As DataRow In parentRow.GetChildRows("ParentChild")
'...
Next
Next
В вашем случае это означает, что вы можете / должны изменить конструктор в вашем EmployeeCol
классе на что-то вроде этого:
Sub New(employeeId As Integer)
Dim data = Helper.GO_GET_DisplayEmployee(employeeId)
If data?.Tables.Count = 2 Then
For Each employeeRow As DataRow In data.Tables("Employee").Rows
Dim detailsList As New List(Of Details)
For Each detailsRow In employeeRow.GetChildRows("EmployeeDetails")
detailsList.Add(New Details(detailsRow))
Next
Me.Add(New Employee(employeeRow) With {.Details = detailsList.ToArray()})
Next
End If
End Sub
РЕДАКТИРОВАТЬ:
Одна из проблем, с которыми я столкнулся Ранее мы ссылались на тот факт, что внутри типов вашей модели есть код ADO. NET. Это плохой дизайн, но, если вы собираетесь это сделать, вы можете сделать это гораздо более чисто, например:
Imports System.Collections.ObjectModel
Public Class Details
Public Property Address As String
Public Property Salary As Decimal
Public Sub New(row As DataRow)
Address = row.Field(Of String)(NameOf(Address))
Salary = row.Field(Of Decimal)(NameOf(Salary))
End Sub
End Class
Public Class DetailsCollection
Inherits Collection(Of Details)
Public Sub New(table As DataTable)
Me.New(table.Rows.Cast(Of DataRow)())
End Sub
Public Sub New(rows As IEnumerable(Of DataRow))
For Each row In rows
Items.Add(New Details(row))
Next
End Sub
End Class
Public Class Employee
Public Property Id As Integer
Public Property Name As String
Public ReadOnly Property Details As DetailsCollection
Public Sub New(row As DataRow)
Id = row.Field(Of Integer)(NameOf(Id))
Name = row.Field(Of String)(NameOf(Name))
Details = New DetailsCollection(row.GetChildRows($"{NameOf(Employee)}{NameOf(Details)}"))
End Sub
End Class
Public Class EmployeeCollection
Inherits Collection(Of Employee)
Public Sub New(employeeId As Integer)
Me.New(Helper.GO_GET_DisplayEmployee(employeeId).Tables(NameOf(Employee)))
End Sub
Public Sub New(table As DataTable)
Me.New(table.Rows.Cast(Of DataRow)())
End Sub
Public Sub New(rows As IEnumerable(Of DataRow))
For Each row In rows
Items.Add(New Employee(row))
Next
End Sub
End Class
Множество улучшений по сравнению с вашей структурой кода там, но я все равно напишу свой код несколько иначе, если начинать с нуля. Следует отметить, что для DataSet
или DataTables
нет нулевой проверки. Если бы это был я, я бы удостоверился, что метод, который получает данные, всегда возвращает DataSet
, и он всегда содержит два DataTables
. Если в них нет данных, пусть будет так, и в итоге вы получите пустой EmployeeCollection
.