I am using business objects where I create SPT cursors with SendUpdates .T.
I never close my cursors, or I think they are closed after the business objects are destroyed.
this is the fetchdata of the business object:
LPARAMETERS tuMsg, tuPK, tuData
LOCAL lnSelect, llSuccess, lcSleutel, lcSQLJoin
lnSelect = SELECT(0)
llSuccess = .T.
lcSleutel = this.cDataSource + "." + this.cPKFieldname
lcSQLJoin = this.cSQLJoin
WITH this
DO CASE
********************************************************************************************************************
CASE .lCOM
********************************************************************************************************************
** retrieve the indicated record via SPT
LOCAL lcSQL, lnConnectionHandle
IF EMPTY(.cStoredProcedure)
lcSQL = "SELECT " + .cFieldList + SPACE(1) + ;
"FROM " + .cDataSource + SPACE(1) + ;
lcSQLJoin + SPACE(1) + ;
"WHERE " + lcSleutel + "= " + tuPK + SPACE(1)
ELSE
lcSQL = "EXEC " + .cStoredProcedure + " 2, " + TRANSFORM(tuPK) + " "
ENDIF
IF .lMaintainConnection
lnConnectionHandle = .nConnectionHandle
ELSE
LOCAL lcConnectionInfo
lcConnectionInfo = .cConnectionInfo
lnConnectionHandle = SQLCONNECT(&lcConnectionInfo)
ENDIF
llSuccess = SQLEXEC(.nConnectionHandle,lcSQL,.cAlias)>0
IF llSuccess
** populate the tuData parameter, passed here by reference with the XML
CURSORTOXML(.cAlias,"tuData",1,8)
USE IN (.cAlias)
ENDIF
IF !.lMaintainConnection
** disconnect
SQLDISCONNECT(lnConnectionHandle)
ENDIF
IF !llSuccess
**
** CURSORTOXML does basically nothing if ther
** are no records
**
tuData = .cXMLBlankRecord
ENDIF
*********************************************************************************************************************
OTHERWISE
*********************************************************************************************************************
** retrieve the indicated record via SPT
LOCAL lcSQL, llNoData
llNoData = VARTYPE(tuPK) = "C" AND !ISNULL(tuPK) ;
and UPPER(ALLTRIM(tuPK)) == "~NODATA~"
IF EMPTY(.cStoredProcedure)
lcSQL = "SELECT " + .cFieldList + SPACE(1) + ;
"FROM " + .cDataSource + SPACE(1) + ;
lcSQLJoin
ELSE
lcSQL = "EXEC " + .cStoredProcedure + " "
ENDIF
IF llNoData
IF EMPTY(.cStoredProcedure)
lcSQL = "SET FMTONLY ON " + lcSQL + "SET FMTONLY OFF"
ELSE
lcSQL = "SET FMTONLY ON " + SPACE(1) +;
lcSQL + " 1, null " + SPACE(1) +;
"SET FMTONLY OFF"
ENDIF
ELSE
IF EMPTY(.cStoredProcedure)
lcSQL = lcSQL + SPACE(1) + ;
"WHERE " + lcSleutel + "= " + tuPK + SPACE(1)
ELSE
lcSQL = lcSQL + "2, " + TRANSFORM(tuPK) + " "
ENDIF
ENDIF
LOCAL llChanges
llChanges = .F.
IF USED(.cAlias)
SELECT (.cAlias)
IF "2" $ GETFLDSTATE(-1)
llChanges = .T.
ELSE
llChanges = .F.
ENDIF
ENDIF
IF !llChanges && no uncommitted changes
llSuccess = SQLEXEC(.nConnectionHandle,lcSQL,.cAlias)>0
** turn the SPT cursor 'into a remote view' to make updates
** easier in THIS.Save()
IF USED(.cAlias)
.TurnSPTCursorIntoRemoteView()
ENDIF
ELSE
llSuccess = .F.
ENDIF
ENDCASE
ENDWITH
RETURN llSuccess
And I am using two forms, one with a list ("parent" form) and other with the details ("child"

.
In "Child" form I do this :
**********************************************************
LOCAL lcCursorname, llSuccess, lcViewname
lcCursorname = this.bcEmployee.listcursor
lcViewname = this.bcEmployee.cAlias
llSuccess = .T.
TRY
IF USED(lcCursorname)
IF (&lcCursorname..pointer <> thisform.nPointerReq) or;
(!ISNULL(&lcCursorname..pointer) AND ISNULL(thisform.nPointerReq)) or ;
(ISNULL(&lcCursorname..pointer) AND !ISNULL(thisform.nPointerReq))
IF thisform.Validated
m.p_persoon = &lcCursorname..pointer
IF USED(lcViewname)
SELECT (lcViewname)
IF "2" $ GETFLDSTATE(-1)
thisform.setchanged()
thisform.save()
ENDIF
ENDIF
llSuccess=thisform.bcEmployee.fetchdata(.F., TRANSFORM(m.p_persoon), IIF(m.stat,1,0),IIF(m.cont,1,0))
thisform.nPointerReq = m.p_persoon
thisform.Caption = "Personeelsfiche - "+TRANSFORM(viewEmployee.prsnickname)
ENDIF
ENDIF
ENDIF
CATCH TO loException
**error
DO errorhandler WITH loException.ErrorNo, PROGRAM(), loException.Lineno
ENDTRY
RETURN llSuccess
***********************************************************
Note: first I have a ~NODATA~ fetch so that the form already knows the structure of the cursor. Otherwise, data bindings will not work.
I hope this will help :-s