Knowing when a new record is a copy of another record while saving the new record on the backend
Often there are situations when copying a record in the UI you wish to perform additional actions on the backend. Imagine creating a copy of an offer record in a CRM system where on the backend you’d like to duplicate the offer line records as well.
In this case the default functionality of the ProDataset where the only thing you know about a copied record is, that it’s new row (by the ROW-STATE attribute value of ROW-CREATED). The ProDataset just does not distinguish between a brand new row and a copy of another record.
For this purpose, we optionally maintain the field “SmartCopiedFrom” with information about the source record of a copy. To leverage this functionality, the Temp-Table in which you are creating a copy of another record should have a character field named “SmartCopiedFrom”. This character field should not be sourced from a database field.
The field value is (by default) either assigned with the value of the “SmartRecordKey” field column which we maintain for “SmartBusinessEntities” or the return value of the BufferHelper:UniqueFindPredicate method.
You can influence the value that is assigned to the “SmartCopiedFrom” field by overriding the GetCurrentRecordKey method in your custom overrides of both the SmartBusinessEntityAdapter and the SmartDatasetChildAdapter types.
In case of a copied record, the value of this field is accessible in the Business Entity and data access object when saving the Field values. When the ROW-STATE of a record is ROW-CREATED this allows you to distinguish between a copy of an existing record and a brand new record and also provides the information about the source record.
Sample Business Entity Implementation
/*------------------------------------------------------------------------------ Purpose: Provides a hook for high level data validation before Update operations Notes: Invoked during SaveChanges (). When the ERROR flag of the ProDataset is set, the Update operation will be cancelled before writing back the data to the database using the DataAccess object ------------------------------------------------------------------------------*/ METHOD OVERRIDE PUBLIC VOID ValidateData (): DEFINE VARIABLE cEntityKey AS CHARACTER NO-UNDO . DEFINE VARIABLE oRequest AS FetchDataRequest NO-UNDO . DEFINE VARIABLE hSourceDataset AS HANDLE NO-UNDO . DEFINE VARIABLE hQuery AS HANDLE NO-UNDO . DEFINE QUERY qQuery FOR eActivity . /* Preselect, as we are changing the ActivityID of the copied record below */ OPEN QUERY qQuery PRESELECT EACH eActivity . GET FIRST qQuery . DO WHILE NOT QUERY qQuery:QUERY-OFF-END ON ERROR UNDO, THROW: /* Handle copies of the parent record from the UI */ IF ROW-STATE (eActivity) = ROW-CREATED AND eActivity.SmartCopiedFrom > "":U THEN DO ON ERROR UNDO, THROW: /* Turn on tracking changes, we are still in an SaveChanges call, so all modifications will be handled by the Data Access object */ THIS-OBJECT:TrackingChanges = TRUE . /* Assign new ActivityID */ IF CharacterType:IsNullOrEmpty (eActivity.ActivityID) THEN ASSIGN eActivity.ActivityID = GUID . /* Use a distinct Business Entity instance as oterwise we'd be calling into ourselved */ ASSIGN cEntityKey = SUBSTITUTE ("&1&2&3", THIS-OBJECT:GetClass():TypeName, CHR (1), GUID) . /* Fetch Source Record and Children */ ASSIGN oRequest = NEW FetchDataRequest ("eActivity,eActivityAttribute", "for each eActivity " + eActivity.SmartCopiedFrom) . ServiceInterface:FetchData (cEntityKey, oRequest, OUTPUT DATASET-HANDLE hSourceDataset) . ASSIGN hQuery = QueryHelper:CreatePreparedQuery (hSourceDataset::eActivityAttribute:HANDLE) . /* Duplicate child records */ DO WHILE NOT hQuery:QUERY-OFF-END: CREATE eActivityAttribute . ASSIGN eActivityAttribute.ActivityAttributeID = GUID eActivityAttribute.ActivityID = eActivity.ActivityID eActivityAttribute.AttributeID = hSourceDataset::eActivityAttribute::AttributeID eActivityAttribute.Name = hSourceDataset::eActivityAttribute::Name eActivityAttribute.IsMandatory = hSourceDataset::eActivityAttribute::IsMandatory eActivityAttribute.DefaultValue = hSourceDataset::eActivityAttribute::DefaultValue . RELEASE eActivityAttribute . hQuery:GET-NEXT () . END . THIS-OBJECT:TrackingChanges = FALSE . FINALLY: ServiceManager:StopBusinessService (cEntityKey, NotRunningServiceEnum:Ignore) . IF VALID-HANDLE (hSourceDataset) THEN DELETE OBJECT hSourceDataset . hSourceDataset = ? . GarbageCollectorHelper:DeleteObject (hQuery) . END FINALLY. END. FINALLY: GET NEXT qQuery . END FINALLY. END. END METHOD .