MORE INFORMATION
The RDSServer.DataFactory business object provided by RDS has four methods.
However, two are typically found in any given business object: the Query
method, which returns a recordset, and the SubmitChanges method, which
processes and attempts to post any changes made to that recordset. Your
business object will likely need the equivalent of these two methods. In
addition, two others will be handy for validating both the functionality
and installation of your custom business object.
Method 1 - SumInt()
SumInt() tests if the Business Object can be created.
This is a simple method that returns the sum of two integers you provide as
arguments. You would use this method to confirm that the business object
can be created correctly from either the local or the remote client. If it
fails, then either the business object is not correctly registered through
Regsvr32.exe, or additional "safe for..." registry entries may be required
on the server or the client.
Public Function SumInt(FirstInt As Integer, _
SecondInt As Integer) As Integer
SumInt = FirstInt + SecondInt
End Function
Possible causes for failure could include the following:
Method 2 - ReturnRSValue()
ReturnRSValue() tests if the Recordset can be opened.
This method verifies that the connection and query information you are
providing to the business object is correct. It will open but not return
an ADO Recordset. It does return an array of variants for the first record
in the recordset obtained by the GetRows method. If this is successful,
then you know the Recordset you are requesting can be created on the
server, which helps isolate any difficulty from an inability to receive it
on the client.
Following is some sample code for the ReturnRSValue method:
Public Function ReturnRSValue(strConnect As String, _
strQuery As String) As Variant
Dim adoCon1 As New ADODB.Connection
Dim adoRs1 As New ADODB.Recordset
Dim x As Variant ' Variant array to send to the Client
' Open a connection to the Database.
adoCon1.Open strConnect
' Open an ADO Recordset.
adoRs1.Open strQuery, adoCon1, adOpenStatic, adLockBatchOptimistic
' Fill the Variant array using GetRows.
x = adoRs1.GetRows(adGetRowsRest, adBookmarkFirst)
' Return the Variant array to the Client.
ReturnRSValue = x
End Function<BR/>
Possible causes of failure could include the following:
- If you use ODBC to expose data to RDS, the data source name (DSN) must be a System DSN or a File DSN, not a User DSN.
- The connection or query information is not correct and will not work
whether you are using RDS to expose an ADO recordset or not.
Method 3 - ReturnRS()
ReturnRS() tests if a Recordset can be returned.
This method returns the recordset that ReturnRSValue() opened. This is
actually an archetype method for a business object, and equivalent to the
RDSServer.DataFactory's Query() method. However, because you are
implementing this method yourself, you can take advantage of the full ADO
Object model, such as using the Command object to open a parameterized
stored procedure. The DataFactory would not be able to do this as it just
creates a standalone Recordset object. However, you should open the exact
same kind of recordset in ReturnRSValue() as ReturnRS().
Following is some sample code for this method:
Public Function ReturnRS(strConnect As String, _
strQuery As String) As ADODB.Recordset
Dim adoCon1 As New ADODB.Connection
Dim adoRs1 As New ADODB.Recordset
' Set the CursorLocation to adUseClient to return an
' ADORecordset to an RDS DataControl.
adoCon1.CursorLocation = adUseClient
' Open ADO Connection with passed in connect string.
adoCon1.Open strConnect
' Open ADO Recordset with passed in SQL string.
adoRs1.Open strQuery, adoCon1, adOpenKeyset, adLockBatchOptimistic
' Return ADO Recordset object to Client.
' (Returns the actual recordset not just a pointer to it).
Set ReturnRS = adoRs1
' Can not close the ADO Recordset object here,
' but it can be disassociated.
Set adoRs1.ActiveConnection = Nothing
' Close ADO Connection object.
adoCon1.Close
End Function
Method 4 - EnhancedSubmit()
EnhancedSubmit() sends changes back to the DataStore.
This method accepts a recordset and uses it to re-open a connection to the
underlying DataStore and submit, in batch, any of the changes you may have
made to that recordset. For any records that were not posted to the
DataStore, it provides details indicating why the failure may have
occurred. It also returns a second recordset that contains just the records
that failed to be posted to the DataStore.
This is actually an archetype method for a business object, and is a
superset of the functionality found in the SubmitChanges() method of the
RDS.DataControl and RDSServer.DataFactory.
Note that the method checks for the occurrence of error 3617, an
undocumented RDS error. This may, depending upon the development
environment you use, come back as either 0x80040E21 or -2147217887.
Following is some sample code for this method:
Public Function EnhancedSubmit(strConnect As String, _
rs As ADODB.Recordset, _
nPosted As Integer, _
vStatus() As Variant)
Dim i As Integer
Dim s As String
dim nConflict as integer
Dim r As New ADODB.Recordset
On Error GoTo ErrCond
s = ""
nPosted = 0
nConflict = 0
' Re-establish connection, submit changes &
' count # affected records
r.Open rs, strConnect
r.UpdateBatch adAffectAll ' Send in modifications
r.Filter = adFilterAffectedRecords '
nPosted = rs.RecordCount
' Determine if there are any conflicts and what type...
ReDim vStatus(r.RecordCount)
i = 0
r.MoveFirst
While r.EOF = False
vStatus(i) = r.Fields(0).value & ": "
CheckStatus r.status, vStatus(i)
' Only report back errors, not accepted or unmodified recs(!)
If (r.status <> adRecOK) And (r.status <> adRecUnmodified) Then
If Len(s) > 0 Then s = s & vbCrLf
s = s & vStatus(i)
nConflict = nConflict + 1
End If
r.MoveNext
i = i + 1
Wend
r.Close
Set r = Nothing
' Set message to return to client
If Len(s) = 0 Then
s = s & "Success! " & Str(nPosted) & " Records Posted."
Else
s = s & vbCrLf & _
"Attempted to Post " & Str(nPosted) & " Records, " & _
Str(nConflict) & " Conflicts Encountered(!)"
End If
EnhancedSubmit = s
Exit Function
ErrCond:
Select Case Err.Number
Case -2147217887 ' Raised when ALL records conflict
s = "Conflicts Occurred in UpdateBatch!"
Resume Next
Case Else
Test4_EnhancedSubmit = "FAILURE " & Str(Err.Number) & _
"--" & Err.Description
End Select
End Function
The CheckStatus subroutine mentioned in the preceding code above is provided in the RDS series of samples listed in the references section and builds a string based on the flags that are set in the Recordset.Status property. You can use this to see why a given record failed. A variation on this conflict resolution code is provided in the RDS* series of samples, as well as the RDSENSUB sample also listed below.
General Diagnosis and Debugging Tips
Using a Local Client
When you write your client, you will not be able to step into the business
object if RDS is used over HTTP to invoke it. You should consider the
advantages of writing a local client which just instantiates the business
object independent of RDS. This is easily done for Visual Basic for
Applications, C++, or Java; however, if you are using VBScript, you should
consider writing a Visual Basic Local Client to get the same effect.
This lets you validate the functionality of your business object, and debug
any issues that might be there. Especially for Visual Basic-based business
objects, as the compilation doesn't always catch syntax errors that the
more rigorous C++ or Java Compilers would prevent.
Whatever methods the remote client using RDS invokes, you should also
invoke with your local client to ensure the validation of the code within
the business object.
However, there will be some differences in behavior with a local client.
For example, the recordset MarshalOptions property will have no effect in a
local client. Consider this code:
rs.MarshalOptions = adMarshalModifiedOnly
This tells RDS to submit records only to the business object (custom or
default) that are changed or added (and of course indicate any deletions
that may have occurred). With your local client, as you are bypassing RDS,
there is no marshalling; therefore, this property has no affect. The entire
recordset is passed to the business object, not just the modified records.