我有一个VB6应用程序,我试图避免插入一个重复的PIN号码。但我的代码总是保存重复的条目。
这是我目前的代码:
Public Function IsPIN_NOExists(ByVal TableName As String, _
ByRef EmployeeCode As String, ByVal FieldName As String, ByVal DataToCheck As String, _
Optional ByVal CodeFieldName As String, Optional ByVal CodeFieldValue As String) As Boolean
TableName = UCase$(Trim$(TableName))
EmployeeCode = Trim$(EmployeeCode)
On Error GoTo ErrorHandle
Dim lstrSQL1 As String
Dim lrsTemp1 As ADODB.Recordset
lstrSQL1 = " Select " & FieldName & " from " & TableName & " Where PIN_NO =" & DataToCheck & ""
If Len(Trim$(CodeFieldName)) <> 0 And Len(Trim$(CodeFieldValue)) <> 0 Then
lstrSQL1 = lstrSQL1 & " AND " & CodeFieldName & " <> '" & CodeFieldValue & "'"
End If
Set lrsTemp1 = cObjDBConn.ExecuteSQL(lstrSQL1)
If lrsTemp1 Is Nothing Then
IsPIN_NOExists = False
ElseIf Not (lrsTemp1.BOF And lrsTemp1.EOF) Then
IsPIN_NOExists = True
lrsTemp1.MoveFirst
EmployeeCode = lrsTemp1.Fields("EMPLOYEE_CODE")
MsgBox (EmployeeCode)
ElseIf lrsTemp1.RecordCount = 0 Then
IsPIN_NOExists = False
Else
IsPIN_NOExists = False
End If
If lrsTemp1.State = adStateOpen Then lrsTemp1.Close
Set lrsTemp1 = Nothing
Exit Function
ErrorHandle:
IsPIN_NOExists = False
End Function
这是我的函数调用代码:
If Trim$(TxtPINno.text) <> "" And Trim$(TxtPINno.text) <> "-" Then
'If gObjValidation.IsCodeExists(fstrTableName, gEmployerCode, "PIN_NO", Trim$(TxtPINno.text)) = True Then
If gobjValidation.IsDescriptionExists(fstrTableName, gEmployerCode, "PIN_NO", Trim$(TxtPINno.text), "EMPLOYEE_ID", Val(txtEmpCode.Tag)) = True Then
If gobjValidation.IsPIN_NOExists(fstrTableName, gEmployeeCode, "EMPLOYEE_CODE", _
Trim$(TxtPINno.text)) = True Then
MsgBox (gEmployeeCode)
Call MessageBox("This PIN Number is already existing for another employee. Cannot enter duplicate number!", OKOnly, Information, DefaultButton1, Me.Caption)
sstInformationTab.Tab = 0
If TxtPINno.Enabled = True Then TxtPINno.SetFocus
CheckAllValidations = False
Exit Function
End If
End If
End If
如何修复此代码以避免输入重复的条目?
编辑:添加ExecuteSQL功能代码
Public Function ExecuteSQL(ByVal SQLQueryStatement As String) As ADODB.Recordset
On Error GoTo ErrorHandler
Dim lrs As ADODB.Recordset
cintDBHitCtr = cintDBHitCtr + 1
Set lrs = DBConnection.Execute(SQLQueryStatement, , adCmdText)
Set lrs.ActiveConnection = Nothing
Set ExecuteSQL = lrs
Set lrs = Nothing
Exit Function
ErrorHandler:
Set ExecuteSQL = Nothing
Call TrapDatabaseError(SQLQueryStatement, DBConnection.Errors(0), cDBType)
End Function
答案 0 :(得分:0)
看起来你已经在你的功能中抛出了额外的逻辑来试图修复你的问题。这个:
If lrsTemp1 Is Nothing Then
IsPIN_NOExists = False
ElseIf Not (lrsTemp1.BOF And lrsTemp1.EOF) Then
IsPIN_NOExists = True
lrsTemp1.MoveFirst
EmployeeCode = lrsTemp1.Fields("EMPLOYEE_CODE")
MsgBox (EmployeeCode)
ElseIf lrsTemp1.RecordCount = 0 Then
IsPIN_NOExists = False
Else
IsPIN_NOExists = False
End If
剥离所有无关的逻辑,可以替换为:
With lrsTemp1
IsPIN_NOExists = Not (.BOF And .EOF)
If IsPIN_NOExists Then
EmployeeCode = lrsTemp1.Fields("EMPLOYEE_CODE")
End If
End With
(据推测,你所有的MsgBox都试图解决错误,所以可以将它们排除在外。)
现在,您的函数中的逻辑用简单的英语表示&#34;如果数据库中存在PIN,则返回true。&#34;查看您的调用代码,您的普通英语逻辑是&#34;如果该函数返回true,则告诉用户PIN已经存在。&#34;由于此逻辑是正确的,因此您的错误位于代码中的其他位置。
您的错误很可能是代码本身的某个地方。禁用你的错误处理程序(只是注释掉#34;错误&#34;语句)你可能会发现你在另一行上得到错误。作为一般规则,不要在代码中放置错误处理程序,直到您确定它按预期工作。错误处理程序适用于用户,而不是开发人员。
设置错误处理程序的方式,如果出现错误,代码将继续添加重复错误,这是您描述的问题。所以这似乎是你的问题。现在,我不想冒犯,我还必须告诉你,这是一个非常糟糕(可怕,甚至)的错误处理设计。您的简单英语逻辑是&#34;如果有错误,请告诉主叫代码您没有找到重复的密钥。&#34;那不太好,是吗? :)例如,如果您的SQL语句中有错误,那么您的代码将插入重复的PIN。
此外,如果 存在,当您返回true时,您的功能听起来像&#34; PIN不存在&#34;考虑将其重命名为&#34; PIN_IsDuplicate&#34;或者更好(也就是说,更符合标准命名约定)&#34; IsDuplicatePIN&#34;。
*****编辑*****
好的,我相信我有你的解决方案。如果你过于认真地清理&#34;清理&#34;你的开放对象引用,你可能会在使用它们之前放弃它们。在这种情况下,您试图断开与记录集的活动连接,因为您的错误印象是只有在首次从记录集中提取数据时才需要连接。虽然在.Net世界中也是如此,但如果你专门设置一个断开连接的记录集,那么在VB6世界中就是如此。&#34;
你的问题在于这行代码:
Set lrs.ActiveConnection = Nothing
执行此操作时,您将收到错误(如果禁用错误处理程序)&#34;对象打开时不允许操作。&#34;这意味着只要记录集处于打开状态,您必须保持与数据库的连接,直到您关闭它或直到该功能结束为止。
跟踪代码,如果通过尝试销毁连接在此行上出现错误,则调用错误处理程序。错误处理程序告诉函数返回一个指向调用函数的空对象指针。所以,在调用函数中,这行代码:
Set lrsTemp1 = cObjDBConn.ExecuteSQL(lstrSQL1)
实际上将lrsTemp1设置为Nothing。因此,满足您的If块的第一个条件,并且您的函数按照指示返回False。这给出了你可以理解的令人困惑的模糊行为。
所以,这里有什么可以带走的。首先,错误处理程序适用于用户,而不适用于开发人员。它们应该是编码过程的最后一步,因为它们将运行时错误转化为难以找到的逻辑错误。如果您发现在具有错误处理程序的代码中存在错误,则第一步是禁用所有错误处理程序。要执行此操作,请转到工具/选项/常规,然后选择中断所有错误。这将导致运行时忽略错误处理程序。
接下来,不要把事情做好。早期版本的VB中有许多误导的专业知识表明你需要这样做。实际上,VB运行时在释放超出范围的对象引用方面要好得多。除了一些您不太可能遇到的非常明确的情况之外,它会自动执行此操作。所以,摆脱你所有的&#34; Set Object = Nothing&#34;声明。你不需要它们,而且你发现它们会导致错误。
然而,有一件事是有用的是在完成使用后明确关闭连接(调用连接对象的Close方法)。删除Recordset的ActiveConnection属性并不关闭连接,它只是说记录集不再想要使用它。此外,如果您通过将连接变量设置为空而退出使用它,则服务器不会自动被通知连接已关闭。它最终会解决这个问题,但你可以通过代码来节省资源。
最后,更清楚地了解不同类型的游标。默认的CursorType是adOpenForwardOnly,一个仅支持MoveFirst和MoveNext的游标。这是最简单的一个,适用于选择单个值(如您所示)或从上到下遍历记录集(例如,在使用记录集的内容填充列表框时)。在关闭记录集之前,此游标必须保持连接到数据库,这就是当您尝试删除活动连接时出现错误的原因。
如果需要在断开数据库连接后仍可使用的记录集,则需要客户端记录集,并且需要将CursorLocation属性设置为adUseClient。这只能有一个adOpenStatic的CursorType,它是一个完全可遍历的(支持向后,向前,多个记录等)不可更新的光标 - 一个&#34;静态&#34;或&#34;快照&#34;光标。 (如果将CursorLocation属性设置为adUseClient,CursorType将自动强制为adOpenStatic。)
如果要完成所有这些操作,则无法使用Connection对象的Execute方法。相反,您必须使用Recordset的Open方法。这里有一些代码可以将authors表从SQL Server pubs示例数据库中拉入断开连接的记录集,并将所有姓氏打印到调试窗口:
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open "Provider=SQLOLEDB.1;Persist Security Info=False;Data Source=.\SQLEXPRESS;Initial Catalog=pubs;Integrated Security=SSPI;"
Set rs = New ADODB.Recordset
With rs
.CursorLocation = adUseClient
.Open "select * from authors", cn, adOpenStatic
Set .ActiveConnection = Nothing
cn.Close
Do Until .EOF
Debug.Print .Fields("au_lname")
.MoveNext
Loop
.MoveFirst
End With