我遇到的问题在以下代码中。该函数适用于ControlCaption实体类,但我必须为我需要读取的每个其他实体类复制并粘贴它,然后将ControlCaption更改为新的类名(我不喜欢在我不知道时重复代码)不得不)。因为还有一个更新/插入值的函数,我试图将公共对象设置为等于类(即Public SomeClass as Object = New ControlCaption),但是IDE抱怨它。
以下是代码:
Public Function SelectList(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of ControlCaption)
Dim strConnectionString As String = ConnectionString() '--Creates the connection string
Dim intLineNumber As Integer = 0
Dim InfoList As New List(Of ControlCaption) '--List of classes being returned
Try
If DatabaseType = SQLServer Then '--User indicated previously that a SQL Server was being used
Using myConnection As New SqlClient.SqlConnection(strConnectionString)
myConnection.Open()
Using myCommand As New SqlClient.SqlCommand(SQLString, myConnection)
Using myReader = myCommand.ExecuteReader
Do While myReader.Read
InfoList.Add(New ControlCaption()) '--Add a new element to the list
'--The next couple of lines need System.Reflection to be imported to work
'--The following for statement goes through each property in a class and assigns
'--the database value with the same name to the property. (Required to use entity classes)
Dim TheObject As New ControlCaption
Dim TheType As Type = TheObject.GetType()
Dim Properties() As PropertyInfo = TheType.GetProperties()
For Each Prop As PropertyInfo In properties
Try
If UCase(Prop.Name) <> "ITEM" Then
If TypeOf (myReader.Item(Prop.Name)) Is DateTime Then
'--Convert value to date
InfoList(InfoList.Count - 1).Item(Prop.Name) = CDate(IIf((myReader.Item(Prop.Name).ToString & String.Empty) = vbNullString, "1/1/1900", myReader.Item(Prop.Name).ToString))
Else
InfoList(InfoList.Count - 1).Item(Prop.Name) = myReader.Item(Prop.Name).ToString & String.Empty
End If
End If
Catch ex As Exception
End Try
Next
Loop
End Using
End Using
If myConnection.State <> ConnectionState.Closed Then
myConnection.Close()
End If
Return InfoList
End Using
ElseIf DatabaseType = AccessDatabase Then
Using myConnection As New OleDb.OleDbConnection(strConnectionString)
myConnection.Open()
Using myCommand As New OleDb.OleDbCommand(SQLString, myConnection)
Using myReader = myCommand.ExecuteReader
Do While myReader.Read
InfoList.Add(New ControlCaption())
Dim TheObject As New ControlCaption
Dim TheType As Type = TheObject.GetType()
Dim Properties() As PropertyInfo = TheType.GetProperties()
For Each Prop As PropertyInfo In properties
Try
If UCase(Prop.Name) <> "ITEM" Then
If TypeOf (myReader.Item(Prop.Name)) Is DateTime Then
InfoList(InfoList.Count - 1).Item(Prop.Name) = CDate(IIf((myReader.Item(Prop.Name).ToString & String.Empty) = vbNullString, "1/1/1900", myReader.Item("DateModified").ToString))
Else
InfoList(InfoList.Count - 1).Item(Prop.Name) = myReader.Item(Prop.Name).ToString & String.Empty
End If
End If
Catch ex As Exception
End Try
Next
Loop
End Using
End Using
If myConnection.State <> ConnectionState.Closed Then
myConnection.Close()
End If
Return InfoList
End Using
Else
Return Nothing
End If
Catch ex As Exception
Return Nothing
End Try
End Function
我觉得有必要让这个功能接受任何课程,但我还没有想出办法。
有没有人对如何使这项工作有任何建议?任何改进建议也会有所帮助。
谢谢。
对于任何有兴趣的人,这是最终生成的代码:
Public Function SelectList(Of EntityClass As New)(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of EntityClass)
Try
Dim Entities As New List(Of EntityClass)()
Using Connection As New SqlClient.SqlConnection(ConnectionString)
Using Command As New SqlClient.SqlCommand(SQLString, Connection)
Connection.Open()
Using Reader = Command.ExecuteReader()
Dim Properties = GetType(EntityClass).GetProperties()
Do While Reader.Read
Dim Entity = CreateEntity(Of EntityClass)(Reader, Properties)
Entities.Add(Entity)
Loop
End Using
End Using
End Using
Return Entities
Catch ex As Exception
MsgBox(Err.Description)
Return Nothing
End Try
End Function
Private Function CreateEntity(Of PassedEntity As New)(ByVal reader As DbDataReader, ByVal properties As PropertyInfo()) As PassedEntity
Dim Entity As New PassedEntity()
For Each _Property As PropertyInfo In properties
If _Property.Name.ToUpper() = "ITEM" Then Continue For
Dim value = reader.Item(_Property.Name)
_Property.SetValue(Entity, value, Nothing)
Next
End Function
答案 0 :(得分:1)
看起来像是#34; New&#34;限制。
&#34;新&#34;约束将提供创建给定类型的新实例的可能性。
Public Function SelectList(Of T As New)(query As String ) As List(Of T)
Dim list As New List(Of T)()
' Somewhere in the rows loop
Dim item = New T()
' Fill properties
list.Add(item)
Return list
End Function
如果您讨厌重复的代码,那么您可以使用DbDataReader
类删除一些重复,这是SqlDataReader
和OleDbDataReader
的基类。
Private Function CreateEntity<(Of T As New)(reader As DbDataReader,
properties As PropertyInfo()) As T
Dim entity As New T()
For Each property As PropertyInfo In properties
If property.Name.ToUpper() = "ITEM" Then Continue For
Dim value = reader.Item(property.Name)
' Should work if property type is correspondent .NET type of sql column type
' For null values property should be of Nullable type
property.SetValue(entity, value)
' If not - use your logic
Next
End Function
在阅读逻辑中使用此功能。请注意,您不需要在每个循环中运行Type.GetProperties()
- 为类型获取一次并重新生成相同的集合
Public Function SelectList(Of T As New)(query As String ) As List(Of T)
Dim entities As New List(Of T)()
Using connection As New SqlConnection(connectionString)
Using command As new SqlCommand(query, connection)
connection.Open()
Using reader = command.ExecuteReader()
Dim properties = GetType(T).GetProperties()
Do While reader.Read()
Dim entity = CreateEntity(reader, properties)
list.Add(entity)
Loop
End Using
' No need for closing connection explicitly - End Using - will handle it
End Using
End Using
Return entities
End Function
答案 1 :(得分:0)
只需将函数参数设置为Object
类型,然后可以将其传递给任何对象类型。例如:
Public Function SelectList(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of Object)
答案 2 :(得分:0)
使其成为通用的。只需返回可以实例化的对象列表。
它将被称为:
Dim myFoo As List(Of Foo) = SelectList(Of Foo)("Select * FROM Foo")
这是新代码
Public Function SelectList(Of T As New)(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of T)
Dim InfoList As New List(Of T) '--List of classes being returned
Dim connectionType = If(DatabaseType = SQLServer, connectionType.MsSql, connectionType.MsAccess)
Try
Using myConnection = getConnection(connectionType, ConnectionString())
myConnection.Open()
Using myCommand = getCommand(connectionType, SQLString, myConnection)
Using myReader = myCommand.ExecuteReader
Do While myReader.Read
Dim TheObject As New T()
InfoList.Add(TheObject) '--Add a new element to the list
Dim TheType As Type = TheObject.GetType()
Dim Properties() As PropertyInfo = TheType.GetProperties()
For Each Prop As PropertyInfo In Properties
Try
If UCase(Prop.Name) <> "ITEM" Then
Prop.SetValue(TheObject, Convert.ChangeType(myReader.Item(Prop.Name), Prop.PropertyType), Nothing)
End If
Catch
End Try
Next
Loop
End Using
End Using
Return InfoList
End Using
Catch ex As Exception
Return Nothing
End Try
End Function
哦,等等,这里也有很多其他的变化!我无法想到你复制函数几乎和复制查询代码一样多,所以我做了一个循环。使用这些函数来创建IDbConnection
和IDbCommand
个对象,因为其余代码是相同的(并且它们实际上只是调用这些接口可用的函数)。
Private Function getConnection(connectionType As ConnectionType, connectionString As String) As IDbConnection
Select Case connectionType
Case ConnectionType.MsSql
Return New SqlClient.SqlConnection(connectionString)
Case ConnectionType.MsAccess
Return New OleDb.OleDbConnection(connectionString)
Case Else
Return Nothing
End Select
End Function
Private Function getCommand(connectionType As ConnectionType, commandString As String, connection As IDbConnection) As IDbCommand
Select Case connectionType
Case ConnectionType.MsSql
Return New SqlClient.SqlCommand()
Case ConnectionType.MsAccess
Return New OleDb.OleDbCommand()
Case Else
Return Nothing
End Select
End Function
Private Enum ConnectionType
MsSql
MsAccess
End Enum
(如果您要添加另一种连接类型,只要它实现这些接口就很简单。)
可以简化属性设置代码,假设日期是标准格式,则只需要一行来设置所有属性
Prop.SetValue(TheObject, Convert.ChangeType(myReader.Item(Prop.Name), Prop.PropertyType), Nothing)
此外,您可以看到没有理由在那里创建两个 ControlCaption
个对象...
最后,您不需要显式关闭连接,因为您已经在使用块中正确地将其连接起来。