As part of the Relativity Services API (RSAPI) Deprecation, content on this page referring to the RSAPI and the Patient Tracker application is in the process of being deprecated and will no longer be supported. For more information and alternative APIs, see RSAPI deprecation process.

Pre Save event handlers

Pre Save event handlers execute after a user changes field values and clicks the Save or Save & Next button in Relativity. They run before the data on the object is written to the database, so you can use them to manipulate information before it's stored. These event handlers are supported on document objects and Relativity Dynamic Objects (RDOs). If the criteria for a pre-save process aren't met, you can cancel the operation.

For example, you can use Pre Save event handlers for the following tasks:

  • Validating data.
  • Auto-updating field values.
  • Adding additional data during a save operation for coded information.

See this related page:

Guidelines for Pre Save event handlers

Use these guidelines when developing Pre Save event handlers:

  • Create a new class in Visual Studio.

    Note: You can also use a template to create this event handler type. For more information, see Visual Studio templates.

  • Add NuGet packages - ensure your Visual Studio project has installed the relevant NuGet packages, including at a minimum the Relativity.EventHandler and Relativity.Api packages.
  • Add a GUID for the event handler - set the System.Runtime.InteropServices.Guid to the GUID identifying your event handler. Use the GUID generator in Visual Studio.
  • Set the CustomAttributes.Description attribute - provide a description that you want to appear in the Relativity UI for the event handler.
  • Inherit from PreSaveEventHandler – extend the PreSaveEventHandler base class.
  • Override the Execute() method – add your business logic for the event handler to this method. This method runs when your event handler is triggered.
  • Override the RequiredFields property – represents fields that are required on object creation.

    Note: The ActiveArtifact.Fields collection includes the fields returned by the RequiredFields property, and those on the current layout. It also includes the values of these fields.

Code sample for a Pre Save event handler

Review the following code sample for a Pre Save event handler. To download the Patient Tracker application that uses this custom code or to view it in a Visual Studio solution, see Patient Tracker application.

Copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;

namespace PatientTracker.EventHandlers
{
      /// <summary>
      /// This event handler verifies that specific fields have values before saving the patient record to the database.
      /// </summary>
      [kCura.EventHandler.CustomAttributes.Description("Patient field validation pre-save handler")]
      [System.Runtime.InteropServices.Guid("207f6e4e-6204-4df3-8264-d0166cd33a77")]
      public class PatientPreSaveEventHandler : kCura.EventHandler.PreSaveEventHandler
      {
        public static readonly Guid FIRST_NAME_FIELD_GUID = new Guid("EB024552-3A1B-40C1-B4DC-5815C3DD3AD3");
        public static readonly Guid LAST_NAME_FIELD_GUID = new Guid("DA73E11E-9D02-4D29-9D3C-F84E66223B2A");
        public static readonly Guid GENDER_FIELD_GUID = new Guid("04E5F293-A4E1-4DF4-8816-F1E6645AE001");
        public static readonly Guid DATE_OF_BIRTH_FIELD_GUID = new Guid("96BC22AF-F2F6-4C92-AD96-CF08BF9AAB4D");

            public override kCura.EventHandler.Response Execute()
            {
                  //Construct a response object with default values.
                  kCura.EventHandler.Response retVal = new kCura.EventHandler.Response();
                  retVal.Success = true;
                  retVal.Message = string.Empty;
            try
            {
                //Get the First Name field value and ensure that it has a value.
                String firstName = (String)this.ActiveArtifact.Fields[FIRST_NAME_FIELD_GUID.ToString()].Value.Value;
                if (String.IsNullOrWhiteSpace(firstName))
                {
                    throw new FieldMissingException("First Name");
                }
                //Get the Last Name field value and ensure that it has a value.
                String lastName = (String)this.ActiveArtifact.Fields[LAST_NAME_FIELD_GUID.ToString()].Value.Value;
                if (String.IsNullOrWhiteSpace(lastName))
                {
                    throw new FieldMissingException("Last Name");
                }
                //Get the Date of Birth field and ensure that it has a value.
                Boolean dobIsNull = this.ActiveArtifact.Fields[DATE_OF_BIRTH_FIELD_GUID.ToString()].Value.IsNull;
                if (dobIsNull)
                {
                    throw new FieldMissingException("Date of Birth");
                }

                //Get the Gender Single Choice field as a collection and ensure that at least one choice has been selected.
                Boolean genderSelected = false;
                kCura.EventHandler.ChoiceCollection genderField = (kCura.EventHandler.ChoiceCollection)this.ActiveArtifact.Fields[GENDER_FIELD_GUID.ToString()].Value.Value;

                //Loop through all Choices in the collection and ensure that at least one is selected.
                foreach (kCura.EventHandler.Choice genderChoice in genderField)
                {
                    if (genderChoice.IsSelected)
                    {
                        genderSelected = true;
                        break;
                    }
                }

                if (!genderSelected)
                {
                    throw new FieldMissingException("Gender");
                }

            }
                //Catch a FieldMissing exception and show the message to the user.
            catch (FieldMissingException fieldMissingEx)
            {
                retVal.Success = false;
                retVal.Message = fieldMissingEx.Message;
            }
                //Catch a general exception and show the message to the user.
            catch (System.Exception ex)
            {
                retVal.Message = "EXCEPTION: " + ex.ToString();
                retVal.Success = false;
            }
                  return retVal;
            }

            /// <summary>
            /// Ensure that you always have access to these fields in the ActiveArtifact.Fields collection even if they aren't in the current layout.
            /// </summary>
            public override kCura.EventHandler.FieldCollection RequiredFields
            {
                  get
                  {
                        kCura.EventHandler.FieldCollection retVal = new kCura.EventHandler.FieldCollection();
                        retVal.Add(new kCura.EventHandler.Field(FIRST_NAME_FIELD_GUID));
                        retVal.Add(new kCura.EventHandler.Field(LAST_NAME_FIELD_GUID));
                        retVal.Add(new kCura.EventHandler.Field(GENDER_FIELD_GUID));
                retVal.Add(new kCura.EventHandler.Field(DATE_OF_BIRTH_FIELD_GUID));
                        return retVal;
                  }
            }
      }

    public class FieldMissingException : System.Exception
    {
        public FieldMissingException(String missingField) :
            base(String.Format("You must fill in the following field: {0}", missingField))
        {

        }
    }
}