Adding Tasks

Adding a task is almost identical to editing a task, but will require you to implement an additional step.

AddTask - DataModule

Start by implementing the AddTask method in the DataModule.

procedure TClientDataModule.AddNewTask;
var
  leditform: TEditForm;
begin
  leditform := TEditForm.Create(Application);
  try
    leditform.Caption := 'Add New Task';
    tbl_Tasks.Insert;
    if leditform.ShowModal = mrOk then
      tbl_Tasks.Post
    else
      tbl_Tasks.Cancel;
  finally
    leditform.Release;
  end;
end;

Add Task - Client Form

Add another button to the client form and call the AddTask method of the DataModule in its onClick method.

Add Button

procedure TClientForm.btnAddClick(Sender: TObject);
begin
  ClientDataModule.AddTask();
end;

Problem

If you now test your sample app and try to add a new task, you will notice there is a problem when you try to apply the changes.

An Error Occurred

While creating the new task, you didn't set the User field, and the User field on the Task table is set to not allow nulls. The problem is that the client doesn’t actually know what the user ID for the logged-in user is, so this problem has to be solved on the server.

Before implementing the server side solution, set the Required and LogChanges properties for the User field in tbl_Tasks to False. This will ensure that the local client will no longer require a user field in Tasks and will ignore any changes to the user field in existing Tasks.

Run the application, add a task, and try to apply the changes – this time you will see a different error.

Update Failed

This is a standard Data Abstract error dialog telling you that Relativity Server has rejected the update because the User field was not set. Leave the application running so you can try to post this change again once you have fixed the problem.

Solution

All changes that are made in the client get passed to Relativity Server inside the Delta objects. There is one delta object per table. Each delta contains one or more changes. Each delta change contains the old (original) and new (modified) values. Within Relativity Server’s business rule scripting model, you can get access to the deltas and changes before the Relativity Server processes them. Using techniques similar to how you filtered data coming from the Relativity Server, you can now ensure that each new Task has its User field set to the ID of the current user before the Relativity Server tries to post it.

Schema Modeler

Go back to the Relativity Admin Tool and open the Schema Modeler. Expand the SCHEMA tree node and select the Scripts entry. Using the Add Event button, add the beforeProcessDeltaChange script handler.

As its name suggests, the beforeProcessDeltaChange event will be called just before processing a particular change from the delta object for the given table. In this script, you just need to obtain the current user ID from the session and update the delta change User field with its value.

// Called before each change is applied to the database
function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  var userId = session['Login.Id'];
  change.newValues['User'] = userId;
  canRemove = false;
}

Back in your running application, try to apply the changes again and hopefully all will work.

An Improved Solution

Even though the application now works, there is a problem. The beforeProcessDeltaChange script will be run for every change in every delta before it gets processed. If you were to ever start adding records for another table in addition to the Tasks table, this script would try to update the User field on that table as well. You need to solve this by ensuring the delta change is for the Tasks table before you try to set the User field.

// Called before each change is applied to the database
function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  if (delta.name == "Tasks") {
    var userId = session['Login.Id'];
    change.newValues['User'] = userId;
    canRemove = false;
  }
}

Records that are being updated should already have the User field set from when the record was added, so although it doesn't hurt to set it again, it's not very clean or efficient, so you might want to ensure that the script only sets the User field when the delta is for an insert.

// Called before each change is applied to the database
function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  if (delta.name == "Tasks" && change.isInsert) {
    var userId = session['Login.Id'];
    change.newValues['User'] = userId;
    canRemove = false;
  }
}