Delete record - appserver

Posted by vrtik on 14-Jul-2010 04:12

Hi

What i need is to delete a record from database and ultragrid. Here is a piece of code i use.

connectAppServer =

NEW connectAppServer (OUTPUT hdlAppServer).

IF VALID-HANDLE (hdlAppServer) THEN RUN sHeaderGetData.p ON hdlAppServer (OUTPUT DATASET dsHeader).

DELETE OBJECT connectAppServer NO-ERROR.

DELETE OBJECT connectAppServer NO-ERROR.

When delete button is pressed.

When i update records i use Tracking-changes to track all changes and it works fine.

What i don't know is how to use it in case of deleting records. I also tried to use mark-row-state but no success.

Code i want to use after i track changes:

DEFINE VARIABLE hdlHeader AS HANDLE NO-UNDO.

DEFINE VARIABLE hdlChHeader AS HANDLE NO-UNDO.

hdlHeader =

DATASET dsHeader:HANDLE.

CREATE DATASET hdlChHeader.

hdlChHeader:

CREATE-LIKE (hdlHeader).

hdlChHeader:

GET-CHANGES (hdlHeader).

RUN

sHeaderSaveChanges.p ON hdlAppServer (INPUT-OUTPUT DATASET-HANDLE hdlChHeader). - this procedure deletes record from database by using  SAVE-ROW-CHANGES.

if record was deleted then

bsHeader:RemoveCurrent().   bsHeader is a binding source

Can someone help.

Thanks

All Replies

Posted by danielStafford on 14-Jul-2010 07:46

Greetings,

One way to handle a delete is to subscribe to the UltraGrid event "BeforeRowsDeleted".

I have a grid "armsGrid".

armsGrid:BeforeRowsDeleted:Subscribe(THIS-OBJECT:armsGridBeforeRowsDeleted).

If I had a delete button I would invoke armsGrid:DeleteSelectedRows().

/* presenter's method */

METHOD PUBLIC VOID armsGridBeforeRowsDeleted( INPUT sender AS System.Object, INPUT args AS BeforeRowsDeletedEventArgs):

        IF NOT valid-object(sender)

            THEN RETURN.

        args:DisplayPromptMsg = FALSE.

        MESSAGE "Delete the selected row?" VIEW-AS ALERT-BOX QUESTION

            BUTTONS YES-NO UPDATE confirmDelete AS LOGICAL.

        IF NOT confirmDelete

            THEN args:Cancel = TRUE.

        ELSE

        DO:

            DEFINE VARIABLE rRow        AS System.Array NO-UNDO.

            DEFINE VARIABLE rCurrentRow AS UltraGridRow NO-UNDO.

            DEFINE VARIABLE cBufferName AS CHARACTER    NO-UNDO.

            rRow = args:Rows.

            rCurrentRow = CAST(rRow:GetValue(0), UltraGridRow).

            cBufferName = rCurrentRow:Band:Key.

            /* new a temporary model to handle the delete - allows the current UI and model states to remain unchanged

              in the event the delete doesn't happen  - the BE will return a message / error, or have the record deleted */

            DEFINE VARIABLE oArmsModelTmp AS model.armsModel NO-UNDO.

            oArmsModelTmp = NEW model.armsModel().

            /* copy only the current buffer contents */

            oArmsModelTmp:hArmsDS:copy-dataset(oArmsModel:hArmsDS, FALSE, FALSE, FALSE, "", TRUE, "").

            /* deleteRow in the tmp model  */

            oArmsModelTmp:setTrackingChanges(TRUE).

            oArmsModelTmp:DeleteRow(cBufferName).

            oArmsModelTmp:setTrackingChanges(FALSE).

            /* send the dataset to the be */

            oArmsModelTmp:SaveChanges().

            /* if the BE returned a message or an error occurred, the tmp model will throw an error - catch it (below) */

            DELETE OBJECT oArmsModelTmp.

            /* remove the local data - no tracking-changes */

            oArmsModel:setTrackingChanges(FALSE).

            oArmsModel:DeleteRow(cBufferName).

/* in the model, a case statement evaluates cBufferName and then: */

hArmBuffer:buffer-delete(). /* the temp-tables default-buffer-handle */

hRelation = hArmsDS:get-relation(2). /* hArmsDS - the grids binding source handle */

hQuery = hRelation:current-query.

hQuery:delete-result-list-entry().

            oArmsModel:setTrackingChanges(TRUE).

        END.

        RETURN.

        CATCH er AS saveChangesError :

            er:ErrorTitle = "Delete has not been performed!".

            er:ShowError().

            args:Cancel = TRUE.

            DELETE OBJECT oArmsModelTmp NO-ERROR.

            DELETE OBJECT er.

            RETURN.

        END CATCH.

        CATCH exc AS exceptionError :

            exc:ErrorTitle = "Service error!".

            exc:ShowError().

            args:Cancel = TRUE.

            DELETE OBJECT oArmsModelTmp NO-ERROR.

            DELETE OBJECT exc.

            RETURN.

        END CATCH.

        CATCH sysErr AS Progress.Lang.SysError :

            MESSAGE "BeforeRowsDeleted Error: " sysErr:GetMessage(1) VIEW-AS ALERT-BOX.

            args:Cancel = TRUE.

            DELETE OBJECT oArmsModelTmp NO-ERROR.

            DELETE OBJECT sysErr.

            RETURN.

        END CATCH.

    END METHOD.

Posted by Håvard Danielsen on 14-Jul-2010 10:19

Code i want to use after i track changes:

DEFINE VARIABLE hdlHeader AS HANDLE NO-UNDO.

DEFINE VARIABLE hdlChHeader AS HANDLE NO-UNDO.

hdlHeader =

DATASET dsHeader:HANDLE.

CREATE DATASET hdlChHeader.

hdlChHeader:

CREATE-LIKE (hdlHeader).

hdlChHeader:

GET-CHANGES (hdlHeader).

RUN

sHeaderSaveChanges.p ON hdlAppServer (INPUT-OUTPUT DATASET-HANDLE hdlChHeader). - this procedure deletes record from database by using  SAVE-ROW-CHANGES.

This should work if you ensure that your query loops through the before-table in the code that calls SAVE-ROW-CHANGES. Deleted rows does not exist in the actual (after) table. You can use this query to access all changed rows and use the AFTER-BUFFER and AFTER-ROWID attributes to access the actual changed row.

Posted by vrtik on 14-Jul-2010 11:11

It looks like that i've got only problem with setting record-state to record deleted. I did try to use mark-row-state which looks like the easiest way to me.

Posted by Håvard Danielsen on 14-Jul-2010 11:24

The row-state should be set to "deleted" automatically when you delete a record with tracking-changes set to true.

Posted by Admin on 14-Jul-2010 12:34

It looks like that i've got only problem with setting record-state to record deleted. I did try to use mark-row-state which looks like the easiest way to me. 

Doesn't turning on TRACKING-CHANGES on the temp-table and actually deleting the temp-table record do the same job?

Posted by vrtik on 15-Jul-2010 03:48

Yes it does. But it also deletes record. What i need is when user press delete button change row status of the record as deleted but don't physically delete it because it needs to be validated through the app server first to check if user has permission to delete it. If so then the record can be deleted otherwise a message should be displayed.

To achieve this i wanted to set record status to record-delete by using mark-row-state.

I wanted to do it as simple as possible and avoid copying dataset etc. but maybe that's the only way.

Posted by Admin on 15-Jul-2010 04:04

The AppServer needs to validate the Before record. If that fails, flag the before record with the ERROR attribute. Then you still can undo the change and display the ERROR-STRING to inform the user.

Posted by vrtik on 15-Jul-2010 04:52

Maybe this is a silly question but how can i undo it?

As soon as i delete record

Tracking-changes = yes.

delete record.

tracking-changes = no.

the record is not available anymore so i cant find before record to do validation. I think that MARK-ROW-STATE can help me to solve this problem but unfortunately i was not able to use it.

When i update record i have no problem with validation etc. There is problem only when i delete record.

Posted by Admin on 15-Jul-2010 05:14

There is a REJECT-CHANGES (or similar) method on the PDS and the Buffer object handle. They will recreate the TT row from the before table.

Posted by danielStafford on 15-Jul-2010 06:29

Have you defined your temp-table with a before-table?

DEFINE TEMP-TABLE eContact BEFORE-TABLE eContactBefore

     FIELD TenantID as CHARACTER FORMAT "x(64)"

     ...

In save changes procedure on the server you need to run a pre-transaction routine (passing in the the DATASET-HANDLE) before save-row-changes.

PROCEDURE eContactDeletePreTransaction:

     DEFINE INPUT PARAMETER DATASET FOR dsContact.

     FIND FIRST eContactBefore NO-ERROR.

     /* run a validateDeleteProc */

     IF NotCanDelete THEN DO:

          eContactBefore:ERROR-STRING = /* some value from validation */.

          eContactBefore:ERROR = TRUE.

     END.

END.

If there is an error you can set hDataSet:ERROR = YES, return,  and on the client:

IF hDataSet:ERROR THEN DO:

     /* traverse buffers and get the error-string */

     hDataSet:REJECT-CHANGES.

END.

Posted by Håvard Danielsen on 15-Jul-2010 09:51

vrtik wrote:

Maybe this is a silly question but how can i undo it?

As soon as i delete record

Tracking-changes = yes.

delete record.

tracking-changes = no.

the record is not available anymore so i cant find before record to do validation. I think that MARK-ROW-STATE can help me to solve this problem but unfortunately i was not able to use it.

When i update record i have no problem with validation etc. There is problem only when i delete record.

Mike and Daniel have already given you the answer(s), I just want to highlight that what you are trying to accomplish is the normal case that the prodataset and the tracking changes capability and before image buffers are designed for. As you have noticed, the record will be deleted and you cannot find it in the regular (after) buffer. You must use the before buffer both for validation, save-row-changes and reject-changes.

Posted by Admin on 15-Jul-2010 10:04

what you are trying to accomplish is the normal case that the prodataset and the tracking changes capability and before image buffers is designed for.

And the ProDataset rocks

Posted by Peter Judge on 15-Jul-2010 10:19

[[Like]]

Posted by Håvard Danielsen on 15-Jul-2010 11:37

Temp-tables rocks, the ProDataSet rules...

This thread is closed