2013-04-18 36 views
1

目前我有我创建的将允许用户输入的SQL代码,然后将类结果返回到阵列,其中它们可进一步使用一个类。大多数方法使用循环将数据从OleDbDataReader对象传输到数组。处理大量物品时,这可能非常缓慢。OleDbDataReader结果直接阵列

电流法:

Dim SQLdr As OleDbDataReader 'SQL reader 
Dim SQLCmd As New OleDbCommand() 'The SQL Command 
Dim firstline As Boolean 
SQLCmd.Connection = SQLConn 'Sets the Connection to use with the SQL Command 
SQLCmd.CommandText = SQLStr 'Sets the SQL String 
SQLdr = SQLCmd.ExecuteReader 'Gets Data 

再后来..

While (SQLdr.Read) 
    If firstline = True Then 
    'fill headers 
    Do Until j = SQLdr.FieldCount 
     result(j, i) = SQLdr.GetName(j) 
     j = j + 1 
    Loop 
    firstline = False 
    j = 0 
    i = 1 
    End If 

    j = 0 
    Do Until j = SQLdr.FieldCount 
    ReDim Preserve result(result.GetUpperBound(0), result.GetUpperBound(1) + 1) 
    If display = True Then 
     MsgBox(j & ":" & i & SQLdr(j).ToString) 
    End If 
    result(j, i) = SQLdr(j).ToString 
    j = j + 1 
    Loop 

    i = i + 1 
End While 

我想知道是否有一个更直接的方式在那里将结果输出到一个数组..我对不起,但我不知道从哪里开始,如果甚至有可能,或者如果有人曾经尝试过。

+0

我只是想评论说,我希望你检查你的用户输入守卫SQL针对SQL注入。 – Melanie

+0

您可以检查是否可以使用DataTable.Load(IDataReader的)方法。没有阵列,但可能比手动循环更快 – Steve

回答

3

这真的是VB.NET?但是,您不应该使用ReDim Preserve来调整阵列大小。而是使用一个通用的List和它的Add方法。您还应该为数据使用自定义类,以提高可读性,使其更具可重用性并且不易出错。当你不使用Object时,它也会更快,因为它不需要装箱/取消装箱。

这里有一个List(Of User)其中Ùser是具有两个属性的自定义类的实例。

Dim users = New List(Of User) 
Using con = New OleDb.OleDbConnection(connectionString) 
    Using cmd = New OleDb.OleDbCommand("SELECT UserID, UserName FROM dbo.User ORDER BY UserName", con) 
     con.Open() 
     Using rdr = cmd.ExecuteReader() 
      While rdr.Read() 
       Dim user = New User() 
       user.UserID = rdr.GetInt32(0) 
       user.UserName = rdr.GetString(1) 
       users.Add(user) 
      End While 
     End Using 
    End Using 
End Using 

在这里简单的类:

Class User 
    Public Property UserID As Int32 
    Public Property UserName As String 
End Class 

如果你想离开你的代码的动态,你也可以使用一个DataAdapter填充DataTable/DataSet。这样可以简化代码并且效率更高。

Dim table = New DataTable() 
Using con = New OleDb.OleDbConnection(connectionString) 
    Using da = New OleDb.OleDbDataAdapter("SELECT UserID, UserName FROM dbo.User ORDER BY UserName", con) 
     da.Fill(table) 
    End Using 
End Using 
+0

+1。 OP的代码看起来更像旧的VB6。 – Neolisk

+0

这绝对是VB.NET。....我的SQL类的重点是保持动态。你的方法不需要事先知道sql结构吗?当类运行时,输出的数量总是可以变化的,这就是我使用循环的原因。 –

+0

如果需要动态字段,请使用'DataAdapter'来填充'DataTable'。这会简化你的代码。编辑我的答案。我的第一个方法是为记录循环一个'DataReader'。 –

0

感谢史蒂夫最初指引我在正确的方向,也感谢你。我搜索,在这里找到的解决方案:

http://www.vbforums.com/showthread.php?381224-Filling-a-DataTable-using-a-DataReader

我用稍微修改该方法,使得它包括标头并且还输出它作为一个阵列我以前完成。

对于未来这里的人是我的运行在TON更快的加载结果完成的代码:

load_sql(username_, password_, conn_string) 

    If SQLConn.State = ConnectionState.Open Then 
     Dim myDataTable As New DataTable 
     Try 
      Using con As New Odbc.OdbcConnection(conn_string) 
       ' Dim command As New Odbc.OdbcCommand(SQLConn, con) 
       Dim SQLCmd As New OleDbCommand() 
       SQLCmd.Connection = SQLConn 'Sets the Connection to use with the SQL Command 
       SQLCmd.CommandText = SQLStr 'Sets the SQL String 
       Using dr As OleDbDataReader = SQLCmd.ExecuteReader 
        myDataTable.Load(dr) 
       End Using 
      End Using 
     Catch ex As Exception 
      myDataTable = Nothing 
     End Try 


     Dim total_rows As Integer 
     Dim total_columns As Integer 
     total_rows = myDataTable.Rows.Count 
     total_columns = myDataTable.Columns.Count 
     Dim result(total_columns, total_rows) As String 
     Dim i As Integer = 0 
     Dim j As Integer = 0 
     Do Until j = total_columns 'add column headers first 
      result(j, 0) = myDataTable.Columns(j).Caption 
      j = j + 1 
     Loop 

     Do Until i = total_rows 'load data to array 
      RaiseEvent progress(i, total_rows) 
      j = 0 
      Do Until j = total_columns 
       result(j, i + 1) = myDataTable.Rows(i)(j) 
       j = j + 1 
      Loop 

      i = i + 1 
     Loop 
     RaiseEvent progress(total_rows, total_rows) 
     RaiseEvent query_finished(result, queryindex) 'display results 

    End If