Вы можете использовать дженерики, вынимая этот метод из вашего определения типа, что-то вроде этого:
Public Shared Function Make(Of T)(ByVal objDR As dbDataReader) As T
Важная: Это предполагает, что ваши типы имеют все свойства, соответствующие DbDataReader.
Однако, если вам нужно петля через свойство и подобрать соответствующую колонку, вы должны будете использовать отражение от этого типа, а также должны проверить наличие этого конкретного столбца в DbDataReader.
В этом случае, вы можете иметь функцию полезности, чтобы проверить наличие в DbDataReader, что-то вроде этого:
Public Shared Function IfExists(ByVal record As Common.DbDataRecord, ByVal columnName As String) As Boolean
For i As Integer = 0 To record.FieldCount - 1
If record.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase) Then
Return True
End If
Next
Return False
End Function
Где вы рамочные в DbDataReader и пройти каждый DbDataRecord вы передаете отраженное имя свойства как ColumnName.
Я не думаю, что в этом случае отражение должно быть плохой практикой. Конечно, будет некоторое снижение производительности, но вы получите повторное использование кода и DRY. Выбор в конечном счете - ваш.
И да, получите ОРМ, чтобы вывести себя из всего этого.
Update (на основе комментариев):
Я проиллюстрирую это на примере. (Обратите внимание, что это всего лишь примеры и в лучшем случае являются грубыми). Как вы сказали, ваши классы наследуются от общего типа, и свойства вам известны.
Таким образом, ваш базовый класс это:
Public Class ClsType
Public Property Id As String
Public Property Desc As String
End Class
И эти классы наследуют от ClsType
:
Public Class Person
Inherits ClsType
End Class
Public Class Order
Inherits ClsType
End Class
Так вы создаете Utility
класс (или код библиотеки):
Public NotInheritable Class Utility
Public Shared Function Make(Of T As {ClsType, New})(ByVal objDR As Common.DbDataReader) As List(Of T)
Dim result = New List(Of T)
For Each rec As Common.DbDataRecord In objDR
Dim tmp As T = New T
If IfExists(rec, "Id") AndAlso Not rec.IsDBNull(rec.GetOrdinal("Id")) Then tmp.Id = rec.GetString(rec.GetOrdinal("Id"))
If IfExists(rec, "Desc") AndAlso Not rec.IsDBNull(rec.GetOrdinal("Desc")) Then tmp.Desc = rec.GetString(rec.GetOrdinal("Desc"))
result.Add(tmp)
Next
Return result
End Function
Public Shared Function IfExists(ByVal record As Common.DbDataRecord, ByVal columnName As String) As Boolean
For i As Integer = 0 To record.FieldCount - 1
If record.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase) Then
Return True
End If
Next
Return False
End Function
End Class
Теперь, когда вам нужно заполнить данные из datareader для любого класс (обратите внимание, что тип известен вам как на ваш вопрос, и поэтому свойства), вы просто назвать эту утилиту так:
Dim result As List(Of Person) = Nothing
Dim objDR As Common.DbDataReader = Nothing
result = Utility.Make(Of Person)(objDR)
Примечание:
Это основано только исходя из предположения, что тип (ы) и их свойства известны. В таком случае вы можете безопасно жестко закодировать все известные свойства. Конечно, как сказал @tony, если вы измените базу данных, вам придется синхронизировать классы самостоятельно.
Если не, то у вас нет выбора но использовать отражение на T
в методе Make
.
Надеюсь, что это поможет.
вы смотрели на LINQ к SQL ли? –
Как бы код, используя отражение, знал, какой тип был подходящим, основываясь только на считывателе данных? У читателя данных есть свойство, которое каким-то образом определяет тип данных, которые он читает? –
@Steven Doggart, все типы наследуются от clsType i.e. clsType.Make используется всеми типами (PersonType, OrderType и т. Д.). Имеет ли это смысл? – w0051977