有以下场景。我有几个表单,基本上有几个下拉框,列表等。我从一个ms sql数据库的记录填充它们。但是,有没有一种方法可以在应用程序的整个生命周期中只查询一次数据库并将记录存储为类的实例,而不是每次用户打开表单时都进行查询?
连接是这样的:
Sub connection_test()
Dim Cn As ADODB.Connection
Dim Rs As ADODB.Recordset
Dim stSQL As String
stSQL = "SELECT * FROM dbo.Client"
Set Cn = New ADODB.Connection
With Cn
.CursorLocation = adUseClient
.Open CONNECTION_STRING
.CommandTimeout = 0
Set Rs = .Execute(stSQL)
End With
Rs.Close
Cn.Close
Set Rs = Nothing
Set Cn = Nothing
End Sub有人能给我提个解决方案吗?我可以看到交通拥挤带来的所有问题,而且大多数情况下都是不必要的。
发布于 2011-05-14 04:42:26
如果只希望记录集可用,请在标准模块中将变量设置为public
Public Rs As ADODB.Recordset
Sub connection_test()
Dim Cn As ADODB.Connection
Dim sSQL As String
If Rs.State = adStateClosed Then
sSQL = "SELECT * FROM dbo.Client"
Set Cn = New ADODB.Connection
With Cn
.CursorLocation = adUseClient
.Open CONNECTION_STRING
.CommandTimeout = 0
Set Rs = .Execute(sSQL)
End With
End If
End Sub现在,R将在项目中的任何位置都可用。您可以在需要时运行connection_test,如果记录集已关闭,它将创建它。如果没有,你就可以走了。
通常,我的方法是创建自定义类。我将创建一个CClient类,从记录集(或其他地方)填充它,用业务逻辑操作对象,然后将新值写回数据库。这样一来,我的业务逻辑都不依赖于我使用的是ado。我可以切换到文本文件或Excel工作表作为数据存储,而不必担心代码中的所有依赖项。
例如,假设我有一个访问表:
ClientID, Autonumber
ContactFirst, String
ContactLast, String
Company, String
CityState, String
Volume, Double我创建了一个CClient类,表中的每个字段都有一个属性。我还创建了一个CClients类来保存所有的CClient实例。在标准模块中,您可能会看到如下内容
Public gclsClients As CClients
Sub Main()
Set gclsClients = New CClients
'Fill the class
gclsClients.FillFromRS
'change some value
gclsClients.Client(1).Volume = 100
'write back to the database
gclsClients.WriteToDB
End Sub在我改变一个客户端的音量时,你会有更多的代码调用你的用户表单,等等。基本的事情是,加载类,做任何你需要的事情,然后把类数据写回数据库。我不会向您展示所有的类代码,但是在CClients中
Public Sub FillFromRS()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim clsClient As CClient
Const sSQL As String = "SELECT * FROM tblClient"
Set cn = New ADODB.Connection
cn.Open msCON
Set rs = cn.Execute(sSQL)
If Not rs.BOF And Not rs.EOF Then
rs.MoveFirst
Do While Not rs.EOF
Set clsClient = New CClient
With clsClient
.ClientID = rs.Fields("ClientID").Value
.ContactFirst = rs.Fields("ContactFirst").Value
.ContactLast = rs.Fields("ContactLast").Value
.Company = rs.Fields("Company").Value
.CityState = rs.Fields("CityState").Value
.Volume = rs.Fields("Volume").Value
End With
Me.Add clsClient
rs.MoveNext
Loop
End If
End Sub此方法从数据库获取数据并填充一堆CClient实例。也是在CClients中
Public Sub WriteToDB()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim clsClient As CClient
Dim sSQL As String
Set cn = New ADODB.Connection
cn.Open msCON
For Each clsClient In Me
sSQL = BuildUpdateSQL(clsClient)
cn.Execute sSQL
Next clsClient
End Sub
Private Function BuildUpdateSQL(clsClient As CClient)
Dim sReturn As String
With clsClient
sReturn = "UPDATE tblClient SET ContactFirst = '" & .ContactFirst & "',"
sReturn = sReturn & " ContactLast = '" & .ContactLast & "',"
sReturn = sReturn & " Company = '" & .Company & "',"
sReturn = sReturn & " CityState = '" & .CityState & "',"
sReturn = sReturn & " Volume = " & .Volume
sReturn = sReturn & " WHERE ClientID = " & .ClientID & ";"
End With
BuildUpdateSQL = sReturn
End Function此方法遍历所有CClient实例,创建一条UPDATE sql语句并执行它。您需要在CClient中实现某种类型的IsDirty属性,以便只更新发生更改的客户端。CClients和CClient的其余部分是基本的类模块。
您可以多次或少量调用WriteToDB。在一些应用程序中,每当有什么变化时,我都会写下它。在其他情况下,我只在工作簿关闭时写回数据库。这在某种程度上取决于你的应用程序的流程。真正的好处在于,如果您从Access数据库更改为用于数据存储的文本文件,则只需更改为CClients中的方法。其余的代码都使用CClients,并不关心数据存储在哪里。
您可以在此处查看工作簿和Access数据库http://www.dailydoseofexcel.com/excel/ClientClassExample.zip
发布于 2011-05-14 03:59:44
阅读有关断开连接的记录集here的信息。
本文(在示例代码中)确实包含了一件事,但没有强调您必须使用adLockBatchOptimistic。您不必像他们那样使用adOpenForwardOnly。当然,您的Recordset对象必须在sub之外有一个作用域。我会这样做:
Function connection_test() as ADODB.Recordset
Dim Cn As ADODB.Connection
Dim Rs As ADODB.Recordset
Dim stSQL As String
stSQL = "SELECT * FROM dbo.Client"
Set Cn = New ADODB.Connection
With Cn
.Open CONNECTION_STRING
.CommandTimeout = 0
End With
With Rs
.CursorLocation = adUseClient
.LockType = adLockBatchOptimistic
.Open stSQL
Set .ActiveConnection = Nothing
End With
Set connection_test = Rs
'DON'T Close the Recordset
'Rs.Close
Cn.Close
'Destroying the local instance is fine, though
Set Rs = Nothing
Set Cn = Nothing
End Function 当然,您希望添加错误处理;)。然后在调用代码中声明一个Recordset对象,并通过调用函数来实例化它。
https://stackoverflow.com/questions/5996415
复制相似问题