Jag har ett litet bekymmer med en sqlexekveringsfunktion, som ser ut så här
Public Function ExecuteSQL(Optional ByRef rsObject As Recordset) As Long
On Error Goto fn_Err
Dim objConn As New ADODB.Connection
Set objConn = [i]connection...[/i]
Set rsObject = New ADODB.Recordset
If InStr(strSQL, "DELETE") Or InStr(strSQL, "INSERT INTO") Then
objConn.Execute strSQL, lngRecordsAffected, adExecuteNoRecords
ExecuteSQL = lngRecordsAffected
ElseIf InStr(strSQL, "SELECT") Then
rsObject.Open strSQL, objConn, adOpenForwardOnly, adLockReadOnly
ExecuteSQL = rsObject.RecordCount
Else
MsgBox "Ofärdig SQL-funktion..."
End If
fn_Exit:
[b]rsObject.Close: Set rsObject = Nothing[/b] <- skapar bekymmer...
objConn.Close: Set objConn = Nothing
Exit Function
fn_Err:
g_intErrNum = Err.Number
g_strErrDesc = Err.Description
g_strErrorMsg = FormatSQL((strSQL))
g_strFunctionName = "ExecuteSQL"
g_strSourceName = "modGlobalaFunktioner"
Call g_ErrorHandler
Resume fn_Exit
End Function
Givetvis går det inte att stänga ett recordset som inte är öppet, men hur kontrollerar jag om det är öppet eller inte?
Är det, förresten, bra eller dåligt att hantera sql på detta sätt?
edit
Ops! Det här meddelandet skulle ha blivit postat i VB-forumet.
Jag hade nog lagt till en kontrollvariabel, i brist på bättre vetande.
Public Function ExecuteSQL(Optional ByRef rsObject As Recordset) As Long
On Error Goto fn_Err
Dim objConn As New ADODB.Connection
[b]Dim blnOpenRS As Boolean
blnOpenRS = false[/b]
Set objConn = connection...
Set rsObject = New ADODB.Recordset
If InStr("DELETE", strSQL) Or InStr("INSERT INTO", strSQL) Then
objConn.Execute strSQL, lngRecordsAffected, adExecuteNoRecords
ExecuteSQL = lngRecordsAffected
ElseIf InStr("SELECT", strSQL) Then
rsObject.Open strSQL, objConn, adOpenForwardOnly, adLockReadOnly
[b]blnOpenRS = True[/b]
ExecuteSQL = rsObject.RecordCount
Else
MsgBox "Ofärdig SQL-funktion..."
End If
fn_Exit:
[b]If blnOpenRS then rsObject.Close[/b]
Set rsObject = Nothing
objConn.Close: Set objConn = Nothing
Exit Function
fn_Err:
g_intErrNum = Err.Number
g_strErrDesc = Err.Description
g_strErrorMsg = FormatSQL((strSQL))
g_strFunctionName = "ExecuteSQL"
g_strSourceName = "modGlobalaFunktioner"
Call g_ErrorHandler
Resume fn_Exit
End Function
Det finns säkert bättre sätt att lösa det på, men jag gillar de enkla lösningarna. ;)
Jo, jag är medveten om det, men jag fick för mig att byref skulle ta hand om det åt mig... hur gör jag då? Måste funktionen returnera ett recordset för att det ska fungera som jag vill?
Nej, du ska ge 17 i att stänga och förstöra det inne i ExecuteSQL() bara.
Jämför:
' skriv sql-fråga
' skapa recordset
' exekvera sql-fråga, fyll recordset
' stäng och förstör recordset
' försök hämta saker från recordsetet som inte längre finns
Att du gör det i en funktion med ett ByRef-objekt är precis samma som att göra det i den kallande funktionen. Du kan inte använda ett objekt som inte finns liksom. ;)
Så, antingen ser du till att returnera recordsetet från funktionen istället för att använda ByRef, eller så ser du till att inte göra dig av med recordsetet inne i ExecuteSQL(). Jag hade gjort det sistnämnda.
Ok. Nu ser det ut som följer, och det fungerar förvisso
Public Function ExecuteSQL() As ADODB.Recordset
On Error GoTo fn_Err
Dim objConn As New ADODB.Connection
Set ExecuteSQL = New ADODB.Recordset
objConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Lager\Lager.Back-End.dev.mdb;Mode=Share Deny None"
If InStr(strSQL, "INSERT INTO") Or InStr(strSQL, "DELETE FROM") Then
objConn.Execute strSQL, lngRecordsAffected, adExecuteNoRecords
Set ExecuteSQL = Nothing
ElseIf InStr(strSQL, "SELECT") Then
ExecuteSQL.Open strSQL, objConn, adOpenForwardOnly, adLockReadOnly
Else
MsgBox "Okänd SQL-fråga." & vbCrLf & vbCrLf & FormatSQL(strSQL), vbExclamation, "Fel!"
End If
End Function
Men kommer inte det att orsaka minnesläckage? (Hemska tanke)
Public Function ExecuteSQL(Optional ByRef rsObject As Recordset) As Long
On Error Goto fn_Err
Dim objConn As New ADODB.Connection
Set objConn = connection...
Set rsObject = New ADODB.Recordset
If InStr("DELETE", strSQL) Or InStr("INSERT INTO", strSQL) Then
objConn.Execute strSQL, lngRecordsAffected, adExecuteNoRecords
ExecuteSQL = lngRecordsAffected
ElseIf InStr("SELECT", strSQL) Then
rsObject.Open strSQL, objConn, adOpenForwardOnly, adLockReadOnly
ExecuteSQL = rsObject.RecordCount
Else
MsgBox "Ofärdig SQL-funktion..."
End If
fn_Exit:
objConn.Close: Set objConn = Nothing
Exit Function
fn_Err:
g_intErrNum = Err.Number
g_strErrDesc = Err.Description
g_strErrorMsg = FormatSQL((strSQL))
g_strFunctionName = "ExecuteSQL"
g_strSourceName = "modGlobalaFunktioner"
Call g_ErrorHandler
Resume fn_Exit
End Function
, och använder ditt ByRef-recordset så borde du inte få några skräpande objekt. Däremot kan det vara så att du måste byta cursorlocation/cursortyp för att inte förstörandet av ditt connectionobjekt ska riva med sig recordsetet.
Public Function ExecuteSQL() As ADODB.Recordset
On Error GoTo fn_Err
Dim objConn As New ADODB.Connection
[b]Set objTempRS = New ADODB.Recordset[/b]
objConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Lager\Lager.Back-End.dev.mdb;Mode=Share Deny None"
If InStr(strSQL, "INSERT INTO") Or InStr(strSQL, "DELETE FROM") Then
objConn.Execute strSQL, lngRecordsAffected, adExecuteNoRecords
Set ExecuteSQL = Nothing
ElseIf InStr(strSQL, "SELECT") Then
[b]objTempRS[/b].Open strSQL, objConn, adOpenForwardOnly, adLockReadOnly
Else
MsgBox "Okänd SQL-fråga." & vbCrLf & vbCrLf & FormatSQL(strSQL), vbExclamation, "Fel!"
End If
[b] Set ExecuteSQL = objTempRS
objTempRS.Close : Set objTempRS = Nothing
objConn.Close : Set objConn = Nothing[/b]
End Function
Då borde du inte få några läckor / objekt som skräpar.