SET EXCLUSIVE OFF SET MULTILOCKS ON SET DELETED ON CLOSE DATABASES ALL CLEAR oCA=CREATEOBJECT("CACategoriesAdo2") ?oCA.AutoOpen() WAIT WINDOW "Insert/Update/Delete records in the BROWSE" BROWSE NORMAL DEFINE CLASS CACategoriesAdo2 AS CursorAdapter Alias="CACategories" * set data source type, SELECT command and cursor schema DataSourceType="ADO" SelectCmd="select CategoryId, CategoryName, Description from categories" CursorSchema="Id I, Name C(15), Descr M" * These properties must be set in order to send updates using ADODB.Command object InsertCmdDataSourceType="ADO" UpdateCmdDataSourceType="ADO" DeleteCmdDataSourceType="ADO" * We will use custom InsertCmd, UpdateCmd and DeleteCmd * Pass ID field as an output parameter to the #CategoryIns procedure, * It will be automatically updated with new IDENTITY value InsertCmd="EXEC #CategoryIns ?@CACategories.Id OUTPUT, ?CACategories.Name, ?CACategories.Descr" UpdateCmd="EXEC #CategoryUpd ?CACategories.Id, ?OLDVAL('Name','CACategories'), ?CACategories.Name, ?CACategories.Descr" DeleteCmd="EXEC #CategoryDel ?CACategories.Id, ?OLDVAL('Name','CACategories')" PROCEDURE Init LOCAL oCon as ADODB.Connection, oRS as ADODB.Recordset, oCom as ADODB.Command * When object is created, create ADO connection object and connect * to the Northwind database on the local SQL Server oCon=CREATEOBJECT("ADODB.Connection") oCon.Open("Provider=SQLOLEDB.1;Integrated Security=SSPI;Initial Catalog=Northwind;Data Source=(local)") * Create stored procedure for Insert, return new value for CategoryId field * using output parameter @ID TEXT TO cSQL NOSHOW CREATE procedure #CategoryIns @id int OUTPUT, @Name varchar(15), @Descr text AS INSERT into Categories (CategoryName,Description) VALUES (@Name, @Descr) SELECT @id=SCOPE_IDENTITY( ) ENDTEXT oCon.Execute(cSQL) * Create stored procedure for Update, it'll check for update conflicts TEXT TO cSQL NOSHOW CREATE procedure #CategoryUpd @id int, @OldName varchar(15), @Name varchar(15), @Descr text AS SET ANSI_NULLS OFF UPDATE Categories SET CategoryName=@Name,Description=@Descr WHERE CategoryId=@Id AND CategoryName=@OldName IF @@ROWCOUNT=0 AND @@ERROR=0 RAISERROR (' Update conflict.', 16, 1) ENDTEXT oCon.Execute(cSQL) * Create stored procedure for Delete, it'll check for update conflicts TEXT TO cSQL NOSHOW CREATE procedure #CategoryDel @id int, @Name varchar(15) AS SET ANSI_NULLS OFF DELETE Categories WHERE CategoryId=@Id AND CategoryName=@Name IF @@ROWCOUNT=0 AND @@ERROR=0 RAISERROR (' Update conflict.', 16, 1) ENDTEXT oCon.Execute(cSQL) * Create Recordset object and configure it for better fetch performance, * we will not use it for updates oRs=CREATEOBJECT("ADODB.Recordset") oRS.ActiveConnection=oCon oRS.CursorLocation= 2 && adUseServer oRS.CursorType= 0 && adOpenForwardOnly oRS.LockType= 1 && adLockReadOnly this.DataSource=oRS * Create the ADODB.Command object to send updates through oCom=CREATEOBJECT("ADODB.Command") oCom.ActiveConnection=oCon this.InsertCmdDataSource=oCom this.UpdateCmdDataSource=oCom this.DeleteCmdDataSource=oCom ENDPROC FUNCTION AutoOpen() NODEFAULT RETURN this.CursorFill(.T.,.F.,-1) && use schema ENDFUNC * The following events are used only to print * commands that are being executed by the object PROCEDURE BeforeInsert LPARAMETERS cFldState, lForce, cInsertCmd ? ? PROGRAM() ? "cInsertCmd=",cInsertCmd ENDPROC PROCEDURE BeforeUpdate LPARAMETERS cFldState, lForce, nUpdateType, cUpdateInsertCmd, cDeleteCmd ? ? PROGRAM() ? "cUpdateInsertCmd=",cUpdateInsertCmd ? "cDeleteCmd=",cDeleteCmd ENDPROC PROCEDURE BeforeDelete LPARAMETERS cFldState, lForce, cDeleteCmd ? ? PROGRAM() ? "cDeleteCmd=",cDeleteCmd ENDPROC ENDDEFINEThanks,