Quote:
|
quote:But surely there must be a more efficient way.
|
Actually, thatâs pretty much exactly how the pros do it. After an insert, you execute a second stored procedure that does a select on the table to retrieve the new value. Hereâs the âstate-of-the-artâ very general approach to the problem. Code follows. Youâre absolutely right. It takes a lot of code to do it right. Your (great) huge question needs a huge reply.
First, break all of your data access code out of your user interface. UI code, from the data access standpoint, should do nothing but call functions that execute stored procedures. And each function called has one purpose in life: to execute a single stored procedure.
The stored procedure executing functions are members of class objects. Each class object has two purposes in life: data validation, and executing stored procedures that execute only one of the CRUD functions: CREATE (Insert), READ (select), UPDATE, DELETE. One class, one type of sproc.
The UI code and data access classes communicate via global connection and recordset objects variables that live in a VBA standard module.
Iâve written out the bare essentials of this kind of 3-tier approach below. (Took about 2 hours to write 2 classes, a standard module, two stored procedures, and a form module. Its time consuming upfront, but saves you hours down the road as you add stored procedures and class methods. That, along with easier code maintenance and reuseability, along with easier distribution, is where the "efficieny" comes into play).
I didnât include any error handling which is essential to this kind of set up but is a topic in and of itself. Errors are handled a bit differently in classes.
----------------------------------------------------------------------
1. Create 2 stored procedures in the âpubsâ data base on SQL Server. Here are the scripts:
----------------------------------------------------------------------
"CREATE PROC procInsertPublisher(@PubID CHAR(4), " & _
"@PubName VARCHAR(40), " & _
"@City VARCHAR(20), " & _
"@State VARCHAR(2), " & _
"@Country VARCHAR(30)) " & _
"AS " & _
"INSERT INTO publishers (pub_id, pub_name, city, state, country) " & _
"Values (@PubID, @PubName, @City, @State, @Country);"
"CREATE PROC procSelectPublishers AS SELECT * FROM Publishers;"
My pubs database has a column check constraint on the pub_id field, so I need to enter values in the format 99[0-9][0-9] like 9901. Canât remember if I put the constraint there myself or not.
-----------------------------------------------------
2. Create a form with the following controls:
-----------------------------------------------------
txtPubID
txtPubName
txtCity
txtState
txtCountry
cmdInsert
cboPublishers (RowSourceType set to Value list)
----------------------------------------------------------------
3. cmdInsert_Click event and sub LoadPublisher
----------------------------------------------------------------
(One handles the insert, the other the select)
(Notice no data access code in the UI. A recordset is instantiatied, but sent to a class for processing.)
Private m_objInsertData As clsInsertData
Private m_objSelectData As clsSelectData
Private Sub cmdInsert_Click()
Dim lngReturnCode As Long
'Opend global connection objectr
Call EstablishConnection
'Set a reference to the insert data class
Set m_objInsertData = New clsInsertData
'Insert the new publisher. Call InsertPublisher function
'in the claInsertData object.
lngReturnCode = m_objInsertData.InsertPublisher(g_cnn, _
txtPubID.Value, _
txtPubName.Value, _
txtCity.Value, _
txtState.Value, _
txtCountry.Value)
'Ensure we were successful with a uer-defined error.
'If lngReturnCode <> 0 Then
' Some error handling code.
'End If
'ReLoad Employees
Call LoadPublishers
'Remove reference to object
Set m_objInsertData = Nothing
End Sub
Sub LoadPublishers()
Dim lngReturnCode As Long
'Set a reference to the global recordset object
Set g_rst = New ADODB.Recordset
'Set a reference to a clsSelectData object
Set m_objSelectData = New clsSelectData
'Open the recordset
lngReturnCode = m_objSelectData.SelectPublishers(g_cnn, g_rst)
'Was function call successful.
'If lngReturnCode <> 0 Then
' Some error handling code.
'End If
'Load cboPublishers
Do While Not g_rst.EOF
Me.cboPublishers.AddItem g_rst!pub_id
g_rst.MoveNext
Loop
'Close the recordset
g_rst.Close
'Remove objects references
Set g_rst = Nothing
Set m_objSelectData = Nothing
Exit Sub
End Sub
-------------------------------------------------------------------------
4. Create the data-tier classes: clsInsertData and clsSelectData
-------------------------------------------------------------------------
(The class methods return a long (0 for success, 1 for failure. 1 would be returned by your error handler along with strMessage. Data validation happens in the classes as well).
-------------------------
Name: clsInsertData
-------------------------
Public Function InsertPublisher( _
ByRef cnn As ADODB.Connection, _
ByVal strPubID As String, _
ByVal strPubName As String, _
ByVal strCity As String, _
ByVal strState As String, _
ByRef strCountry As String) As Long
Dim blnValidated As Boolean
Dim cmd As ADODB.Command
blnValidated = True
'Validate data to insert. Validate every item to be inserted.
'I just did the PubID field here.
If RTrim(Len(strPubID)) = 0 Then
strMessage = "Pub ID is zero length" & vbCrLf & vbCrLf
blnValidated = False
End If
If RTrim(Len(strPubID)) > 4 Then
strMessage = "Pub ID is greater than 4 characters" & vbCrLf & vbCrLf
blnValidated = False
End If
'Check validation variable
'If Not blnValidated Then
' Some error handling code.
'End If
'Set a reference to the command object
Set cmd = New ADODB.Command
'Set the command object properties
Set cmd.ActiveConnection = cnn
cmd.CommandText = "procInsertPublisher"
cmd.CommandType = adCmdStoredProc
'Create and append the parameters to the parameters collection
cmd.Parameters.Append cmd.CreateParameter("@PubID", _
adVarChar, adParamInput, 4, strPubID)
cmd.Parameters.Append cmd.CreateParameter("@PubName", _
adVarChar, adParamInput, 40, strPubName)
cmd.Parameters.Append cmd.CreateParameter("@City", _
adVarChar, adParamInput, 15, strCity)
cmd.Parameters.Append cmd.CreateParameter("@State", _
adVarChar, adParamInput, 20, strState)
cmd.Parameters.Append cmd.CreateParameter("@Country", _
adVarChar, adParamInput, 20, strCountry)
'Execute the command object
cmd.Execute
'Remove references to objects
Set cmd = Nothing
'Set the return code, return 1 in an error handler.
InsertPublisher = 0
Exit Function
End Function
------------------------------------
Name: clsSelectData
------------------------------------
Public Function SelectPublishers( _
ByRef cnn As ADODB.Connection, _
ByRef rst As ADODB.Recordset) As Long
rst.Open "procSelectPublishers", cnn, adOpenForwardOnly, adLockReadOnly, adCmdStoredProc
'Set the return code
SelectPublishers = 0
Exit Function
End Function
SEE!!! ALL THE DATA ACCESS CODE IS IN THE CLASSES!!! WOO HOO!!!
----------------------------------------------------------------------
5. Create a standard module to open a global connection
----------------------------------------------------------------------
Iâm opening the connection in the form, but typically youâd open it in a login dialog when the app starts.
--------------------------------------------
Name: basConnection Management
--------------------------------------------
Global g_cnn As ADODB.Connection
Global g_rst As ADODB.Recordset
Public Function EstablishConnection() As Boolean
Dim strConnectString As String
Set g_cnn = New ADODB.Connection
strConnectString = "Provider='sqloledb';Data Source='ELIOT';" & _
"Initial Catalog='Pubs';Integrated Security='SSPI';"
g_cnn.Open strConnectString
'Check connection state
If g_cnn.State <> adStateOpen Then
EstablishConnection = False
Else
EstablishConnection = True
End If
Exit Function
End Function
Public Sub TerminateConnection()
On Error Resume Next
g_cnn.Close
g_rst.Close
Set g_cnn = Nothing
Set g_err = Nothing
Set g_rst = Nothing
End Sub
THERE YOU GO!! BASIC N-TIER APP. (VERY BASIC ). Runs great for me. Hope it runs for you too!!
HTH,
Bob