Может кто-нибудь помочь мне дать пример кода, как вызвать этот метод?
Public Shared Function ReadObjects(Of T)(ByVal query As String, ByVal func As Func(Of IDataReader, T)) As IEnumerable(Of T)
Dim outbound As New List(Of T)
Using connection As OleDbConnection = NewConnection()
connection.Open()
Using command As OleDbCommand = New OleDbCommand(query, connection)
command.CommandType = CommandType.Text
command.CommandTimeout = 0
Dim reader As OleDbDataReader = command.ExecuteReader
While reader.Read()
outbound.Add(func.Invoke(reader))
End While
End Using
connection.Close()
End Using
Return outbound
End Function
Я понятия не имел, как это сделать :)
Прежде всего, я бы написал такую функцию:
Public Shared Iterator Function ReadObjects(Of T)(query As String, transform As Func(Of IDataRecord, T), parameters As Action(Of OleDbParameterCollection)) As IEnumerable(Of T)
Using connection As OleDbConnection = NewConnection()
Using command As OleDbCommand = New OleDbCommand(query, connection)
If parameters IsNot Nothing Then parameters(command.Parameters)
command.CommandTimeout = 0
connection.Open()
Dim reader As OleDbDataReader = command.ExecuteReader()
While reader.Read()
Yield transform(reader)
End While
End Using
End Using
End Function
Здесь есть несколько изменений, но самым важным является возможность принимать параметры запроса отдельно от командной строки. В противном случае предыдущий код вынудил бы вас добавить в ваше приложение ОГРОМНЫЕ ШИРОКИЕ УЯЗВИМОСТИ БЕЗОПАСНОСТИ.
Кстати, похоже, что вы спрашиваете, как вызвать метод, и, вероятно, аргумент Func(Of IDataRecord, T)
сбивает с толку... а теперь еще и Action(Of OleDbParameterCollection)
.
Вот как это сделать.
Во-первых, давайте возьмем пример. Допустим, у вас есть таблица Employee
со столбцами для ID
, LastName
и FirstName
. У вас также есть класс с именем Employee
со свойствами, соответствующими именам столбцов. У вас есть переменная с именем lastName
, и вы хотите запустить запрос, чтобы получить все записи из таблицы, в которых значение столбца LastName
соответствует значению переменной lastName
. Затем мы прокручиваем результаты и записываем каждого сотрудника в консоль:
Это будет выглядеть так:
Dim lastName As String = "Bilazon"
Dim SQL As String = "SELECT * FROM Employee WHERE LastName = ?"
Dim employees = ReadObjects(SQL,
Function(e) New Employee() With {ID = e("ID"), LastName = e("LastName"), FirstName = e("FirstName")},
Sub(p) p.Add("?", OleDbType.VarWChar, 25).Value = lastName)
For Each emp As Employee In employees
Console.WriteLine($"ID: {emp.ID}{vbTab}Last Name: {emp.LastName}{vbTab}First Name: {emp.FirstName}")
Next
Встроенные выражения Function
и Sub
выше называются лямбда-выражениями.
Я мог бы сделать этот код немного проще для написания и понимания, добавив метод Shared с именем FromDataRecord()
в мой класс Employee
:
Public Shared Function FromDataRecord(row As IDataRecord) As Employee
Return New Employee() With {
ID = row("ID"),
LastName = row("LastName"),
FirstName = row("FirstName")
}
End Function
Это особенно ценно, когда класс добавляет больше свойств или становится более сложным. Теперь вызов функции тоже можно немного упростить:
Dim lastName As String = "Bilazon"
Dim SQL As String = "SELECT * FROM Employee WHERE LastName = ?"
Dim employees = ReadObjects(SQL, Employee.FromDataRecord,
Sub(p) p.Add("?", OleDbType.VarWChar, 25).Value = lastName)
For Each emp As Employee In employees
Console.WriteLine($"ID: {emp.ID}{vbTab}Last Name: {emp.LastName}{vbTab}First Name: {emp.FirstName}")
Next
Следующий уровень — перемещение метода ReadObjects()
в его собственный модуль (и пометка его как приватного), поэтому вы также пишете общедоступный метод в новом модуле для каждого из запросов, которые хотите выполнить.
Большое спасибо, Джоэл! Некоторое уточнение, если я правильно понимаю, так что e — это экземпляр Employee, а p — экземпляр OleDbDataReader?
e
— текущая строка средства чтения данных. p
— это коллекция .Parameters
OleDbCommand, поэтому вы можете добавлять параметры запроса безопасным способом, а не использовать конкатенацию строк для построения запроса (что очень НЕ безопасно).
@BernBilazon Но это моя вина, что у вас было такое задом наперед ... Я только что заметил, что поместил новый аргумент в определение метода не в том месте (теперь он исправлен в ответе).
Вау, это очень подробно!! Большое спасибо за объяснение. Это делает мой день!
Следующий уровень — перемещение метода ReadObjects()
в его собственный модуль (и пометка его как приватного), так что вы также пишете общедоступный метод в новом модуле для каждого из запросов, которые хотите выполнить.
Запрашивать код для реализации кода вообще не имеет смысла. Этот код уже является кодом. Он уже реализует то, что реализует. Какую настоящую проблему вы пытаетесь решить? Предоставьте ПОЛНОЕ и ЯСНОЕ объяснение.