Relativity Services API (RSAPI) DTOs have been deprecated in 11.3 and are no longer supported. For more information and alternative APIs, see RSAPI deprecation process.

RDO

A Relativity Dynamic Object (RDO) is custom object that you create in a workspace. It has a unique ArtifactTypeID in the workspace where it is created. For more information, see Relativity Objects .

The Services API supports all CRUD and query operations on an RDO.

Starting with 9.5.133.118, you can programmatically interact with admin-level RDOs.

Note: You can also perform a full set of CRUD operations on RDOs using the single-artifact access methods common to all Relativity DTOs. For more information, see Single-artifact access.

This page contains the following information:

Create an RDO

You can add an RDO to Relativity by calling the Create() method on the RDO repository. This code sample use GUIDs to reference Fields, but you can also reference Fields by their names or ArtifactIDs.

public void Create_an_RDO_UsingGUIDs()
{
     try
     {
          using (IRSAPIClient proxy = 
               new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new IntegratedAuthCredentials()))
          {
               proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
                 
               //STEP 1: Define constant values for GUIDs identifying the artifact type, fields, and choices
               const string ARTIFACT_TYPE = "EE5BD2B1-47A8-45CE-AA5B-2115B6DD86A4";
               const string LAST_NAME = "37159592-B5B6-4405-AF74-10B5728890B4";
               const string FIRST_NAME = "3BDC0971-A87C-414E-9A37-FC477279BBAD";
               const string SINGLE_CHOICE_FIELD = "4F06AC67-822A-414F-B6C1-5D4007E998EF";
               const string SINGLE_CHOICE = "4501A308-5E68-4314-AEDC-4DEB527F12A8";
               const string MULTI_CHOICE_FIELD = "C9D1C1E7-61B1-46EE-A35D-406FC9503DE5";
               const string MULTI_CHOICE_1 = "6A1D5E35-B4B3-4962-9EEB-6E6D3016D40C";
               const string MULTI_CHOICE_2 = "E647DF05-2E51-41E7-B6A3-C3F1CD723C54";
               const string USER_FIELD = "C1A2DB49-3282-40CF-84A0-8DEEB4E76764";
               const string SINGLE_OBJECT_FIELD = "68094937-3E3A-42D4-B71B-132C8A4C51F7"; 
               const string MULTI_OBJECT_FIELD = "467D2CDE-7892-4463-9890-805B937E3945";
                
               // STEP 2: Create an RDO DTO and set the ArtifactTypeGuids.
               var dto = new RDO();
               dto.ArtifactTypeGuids.Add(new Guid(ARTIFACT_TYPE));
                 
               // STEP 3: Add FieldValues to the Fields collection. Specify the GUID
                // of the Field that you want to set. Set the FixedLengthText fields.
               dto.Fields.Add(new FieldValue(new Guid(LAST_NAME), "Smith"));
               dto.Fields.Add(new FieldValue(new Guid(FIRST_NAME), "Joe"));
                 
               // Set a SingleChoice Type field to a Choice using the GUID that represents 
               // the Choice artifact.
               dto.Fields.Add(new FieldValue(new Guid(SINGLE_CHOICE_FIELD), new Guid(SINGLE_CHOICE)));
                 
               // Set A MultiChoice field by creating a MultiChoiceFieldValueList as its value.
               // The MultiChoiceFieldValueList contains Choice DTOs, which are set using GUIDs that represent 
               // the Choice artifact.
               var multiChoices = new MultiChoiceFieldValueList(
               new kCura.Relativity.Client.DTOs.Choice(new Guid(MULTI_CHOICE_1)),
               new kCura.Relativity.Client.DTOs.Choice(new Guid(MULTI_CHOICE_2)));
                 
               // Set the UpdateBehavior depending on whether you want to Merge or Replace the new values.
               multiChoices.UpdateBehavior = MultiChoiceUpdateBehavior.Replace;
                 
               // Set the MultiChoice field using its GUID and set the value to the MultiChoiceFieldValueList.
               dto.Fields.Add(new FieldValue(new Guid(MULTI_CHOICE_FIELD), multiChoices));
                 
               // Set a User field to a User DTO.
               dto.Fields.Add(new FieldValue(new Guid(USER_FIELD), 
                    new kCura.Relativity.Client.DTOs.User(1015411)));
                 
               // Set a SingleObject to a DTO for the object. In this example, a SingleObject Field takes a Document.
               var obj = new kCura.Relativity.Client.DTOs.Document(1038372);
               dto.Fields.Add(new FieldValue(new Guid(SINGLE_OBJECT_FIELD), obj));
                 
               // Set a MultiObject to a FieldValueList of the Type of objects. In this example, a MultiObject Field takes instances of RDOs.
               FieldValueList<RDO> objects = new FieldValueList<RDO>();
               objects.Add(new RDO(1067600));
               objects.Add(new RDO(1067613));
               dto.Fields.Add(new FieldValue(new Guid(MULTI_OBJECT_FIELD), objects));
                 
               // STEP 4: Call the Create() method on the RDO Repository.
               WriteResultSet<RDO> writeResults = proxy.Repositories.RDO.Create(dto);
                 
               if (writeResults.Success)
               {
                    Console.WriteLine(string.Format("Object was created with Artifact ID {0}.", writeResults.Results[0].Artifact.ArtifactID));
               }
               else
               {
                    Console.WriteLine(string.Format("An error occurred creating object: {0}", writeResults.Message));
                      
                    for (Int32 i = 0; i <= writeResults.Results.Count - 1; i++)
                    {
                         if (!writeResults.Results[i].Success)
                         {
                              Console.WriteLine(String.Format("An error occurred in create request {0}: {1}", i, writeResults.Results[i].Message));
                         }
                    }
               }
          }
     }
     catch (Exception ex)
     {
          Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
     }
}        

Create an RDO as a child object

You can create an RDO that is a child of another object other than Workspace. You must set the ParentArtifact property of the child object to the DTO Artifact of its parent object as illustrated in this code sample.

// Create an instance of the parent object with ArtifactTypeName “ParentObj”.
            
var rdo = new RDO("ParentObj");
rdo.TextIdentifier = "Test Parent Object";
var parentCreate = proxy.Repositories.RDO.Create(rdo);
 
// Create an instance of the child object with ArtifactTypeName “ChildObj” 
 // and set the ParentArtifact to the parent object instance previously created.
var childRDO = new RDO("ChildObj");
childRDO.TextIdentifier = "Child of Test Parent Object";
childRDO.ParentArtifact = 
     new kCura.Relativity.Client.DTOs.Artifact(parentCreate.Results[0].Artifact.ArtifactID);
var childCreate = proxy.Repositories.RDO.Create(childRDO);
        

Read an RDO

To read Field values, you can use the Read() method on the RDO repository as illustrated in this code sample. Note that after returning the Fields collection, you can use the Get method to obtain the individual field values by specifying either the field name as a string, the field artifact ID as an integer, or the field GUID. This is different from standard Relativity DTOs, where all available fields are predefined by the object type, and the field values can be returned using object properties.

public static bool Read_an_RDO_Using_Repository(IRSAPIClient proxy)
{
    // STEP 1: Call the read method on the RDO Repository
    // Note the use of the constructor to initialize an RDO object to be subsequently read with an already known ArtifactID value. 
    DTOs.RDO employee = new DTOs.RDO(1036225);
    employee.ArtifactTypeID = 1000036;
    employee.Fields = FieldValue.AllFields;

    DTOs.ResultSet<DTOs.RDO> results = new DTOs.ResultSet<DTOs.RDO>();

    try {
        results = proxy.Repositories.RDO.Read(employee);
    }
    catch (Exception ex) {
        Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
        return false;
    }

    //Check for success
    if (!results.Success) {
        Console.WriteLine("An error occurred!");
        Console.WriteLine(results.Message);
        return false;
    }

    // STEP 2: get the artifact from the read results
    employee = results.Results.Single().Artifact;

    FieldValue lastNameField = employee.Fields.Get("Last Name");
    FieldValue employmentLevelField = employee.Fields.Get("Employment Level");
    FieldValue hrRepField = employee.Fields.Get("HR Rep");
    FieldValue skillsInventoryField = employee.Fields.Get("Skills Inventory");
    FieldValue keyDocumentField = employee.Fields.Get("Key Document");
    FieldValue favoriteDocumentsField = employee.Fields.Get("Favorite Documents");

    Console.WriteLine("Artifact: {0} Field: {1} Value: {2}", employee.ArtifactID, lastNameField.Name, lastNameField.ValueAsFixedLengthText);
    Console.WriteLine("Artifact: {0} Field: {1} Value: {2}", employee.ArtifactID, employmentLevelField.Name, employmentLevelField.ValueAsSingleChoice.ArtifactID);

    MultiChoiceFieldValueList multiChoiceList = skillsInventoryField.ValueAsMultipleChoice;
    for (int index = 0; index < multiChoiceList.Count; index++) {
        DTOs.Choice choice = multiChoiceList[index];
        Console.WriteLine("Artifact: {0} Field: {1} Value: {2}", employee.ArtifactID, skillsInventoryField.Name + " " + "Choice " + index, choice.ArtifactID);
    }

    Console.WriteLine("Artifact: {0} Field: {1} Value: {2}", employee.ArtifactID, hrRepField.Name, hrRepField.ValueAsUser.ArtifactID + " - " + hrRepField.ValueAsUser.FullName);

    //Single Object for RDO's will be returned as an Artifact
    DTOs.Artifact documentArtifact = (DTOs.Artifact)keyDocumentField.Value;
    Console.WriteLine("Artifact: {0} Field: {1} Value: {2}", employee.ArtifactID, keyDocumentField.Name, documentArtifact.ArtifactID);

    //Multiple Objects for RDO's will be returned as FieldValueList<Artifact>
    FieldValueList<DTOs.Artifact> multiObject = ((FieldValueList<DTOs.Artifact>) favoriteDocumentsField.Value);
    for (int index = 0; index < multiObject.Count; index++) {
        Int32 id = multiObject[index].ArtifactID;
        Console.WriteLine("Artifact: {0} Field: {1} Value: {2}", employee.ArtifactID, favoriteDocumentsField.Name + " Object " + index, id);
    }

    return true;
} 

Update an RDO

You can use the Update() method on an RDO repository to modify its properties as illustrated in this code sample.

public void Update_RDO_Using_Repository()
{
     try
     {
          using (IRSAPIClient proxy = 
               new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new IntegratedAuthCredentials()))
          {
               proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
                
               // STEP 1: Initialize an RDO DTO and add the FieldValue that you want to update.
               // Note the use of the RDO constructor with the artifact type name ("Employees") and the ArtifactID of the RDO instance to be updated (1067694).    
               RDO artifact = new RDO("Employees", 1067694);
               artifact.Fields.Add(new FieldValue() {Name = "Last Name", Value = "Smith, Jr."});
                
               // STEP 2: Call the Update() method on the RDO respository.
               WriteResultSet<RDO> writeResultSet = proxy.Repositories.RDO.Update(artifact);
                
               if (!writeResultSet.Success)
               {
                    Console.WriteLine("Error: " + writeResultSet.Message);
                     
                    for (Int32 i = 0; i <= writeResultSet.Results.Count - 1; i++)
                    {
                         if (!writeResultSet.Results[i].Success)
                         {
                              Console.WriteLine(String.Format("An error occurred in update request {0}: {1}", i, writeResultSet.Results[i].Message));
                         }
                    }
               }
          }
     }
     catch (Exception ex)
     {
          Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
     }
}
        

Delete an RDO

You can remove an RDO from Relativity by calling the Delete() method on the RDO repository as illustrated in this code sample.

public void Delete_RDO()
{
     using (IRSAPIClient proxy = 
          new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new IntegratedAuthCredentials()))
     {
          try
          {
               proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
                
               //Step 1: Create a DTO for an instance of the "Employees" RDO.
               var dtoToDelete = new RDO("Employees", 1067605);
                
               //Step 2: Call Delete on the RDO Repository and pass the RDO DTO.
               WriteResultSet<RDO> deleteResult = proxy.Repositories.RDO.Delete(dtoToDelete);
                
               if (!deleteResult.Success)
               {
                    Console.WriteLine("Error deleting the object: " + deleteResult.Message);
                     
                    for (Int32 i = 0; i <= deleteResult.Results.Count - 1; i++)
                    {
                         if (!deleteResult.Results[i].Success)
                         {
                              Console.WriteLine(String.Format("An error occurred in delete request {0}: {1}", i,
                                   deleteResult.Results[i].Message));
                         }
                    }
               }
          }
          catch (Exception ex)
          {
               Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
          }
     }
}

Deleting linked objects

When deleting an RDO, you must first delete any linked objects. The following code sample is a Pre Delete event handlers for a custom Book object that may be linked to multiple Hold objects. The event handler performs a query for dependent objects, and, if they exist, deletes them.

[kCura.EventHandler.CustomAttributes.Description("Book Pre-Delete Event Handler")]
[System.Runtime.InteropServices.Guid("0D9375EE-E738-4EA5-A835-E4EAF50404EE")]
class LibraryPreDeleteEventHandler : kCura.EventHandler.PreDeleteEventHandler
{
    public override void Commit()
    {
        List<RDO> holdsToDelete = new List<RDO>();

        ObjectCondition bookCriteria = new ObjectCondition(Utils.HoldGuids.HOLD_TO_BOOK_GUID, ObjectConditionEnum.IsSet);

        kCura.Relativity.Client.DTOs.Query<RDO> query = new Query<RDO>
        {
            ArtifactTypeGuid = Utils.ObjectGuids.HOLD_TYPE_GUID,
            Condition = bookCriteria.Negate()
        };

        query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue(Utils.HoldGuids.ARTIFACT_ID_GUID));

        QueryResultSet<RDO> results = new QueryResultSet<RDO>();

        try
        {
            using (IRSAPIClient proxy = Helper.GetServicesManager().CreateProxy<IRSAPIClient>(ExecutionIdentity.System))
            {
                proxy.APIOptions.WorkspaceID = Helper.GetActiveCaseID();
                results = proxy.Repositories.RDO.Query(query);
                
                foreach (Result<RDO> holdResult in results.Results)
                {
                    holdsToDelete.Add(holdResult.Artifact);
                }

                WriteResultSet<RDO> deleteResult = proxy.Repositories.RDO.Delete(holdsToDelete);
            }
        }
        catch (Exception exception)
        {
            // TODO: Add exception handling
        }
    }

Query for an RDO

This code sample illustrates how to set query conditions, call the Query() method on the RDO repository, and iterate through the result set.

public void Query_an_RDO_Using_Repository()
{
     using (IRSAPIClient proxy = 
          new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new IntegratedAuthCredentials()))
     {
          try
          {
               proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
                
               // STEP 1: Setup your query criteria.
               TextCondition lastNameCriteria = new TextCondition("Last Name", TextConditionEnum.EqualTo, "Smith");
               TextCondition firstNameCriteria = new TextCondition("Name", TextConditionEnum.EqualTo, "Mike");
               CompositeCondition condition = new CompositeCondition(lastNameCriteria, CompositeConditionEnum.And,
                    firstNameCriteria);
                
               kCura.Relativity.Client.DTOs.Query<RDO> query = new Query<RDO> {ArtifactTypeID = 1000030, 
                    Condition = condition};
                
               query.Fields.Add(new FieldValue("Employment Level"));
               query.Fields.Add(new FieldValue("Skills Inventory"));
               query.Fields.Add(new FieldValue("HR Rep"));
               query.Fields.Add(new FieldValue("Last Name"));
               query.Fields.Add(new FieldValue("Name"));
                
               // STEP 2: Call the Query() method on the RDO repository.
               QueryResultSet<RDO> results = new QueryResultSet<RDO>();
               results = proxy.Repositories.RDO.Query(query);
                
               //Check for success.
               if (!results.Success)
               {
                    Console.WriteLine("An error occurred!");
                    Console.WriteLine(results.Message);
               }
                
               // STEP 3: Get the Artifact from the query results.
               RDO employee = results.Results.Single().Artifact;
               Console.WriteLine(">>>" + employee + "<<<");
          }
          catch (Exception ex)
          {
               Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
          }
     }
}        

Admin-level RDOs

When working with admin-level RDO, you must specify -1 as the WorkspaceID in the APIOptions object:

proxy.APIOptions.WorkspaceID = -1;

The subsequent operations - create, read, update, delete, and query - use the same workflow as the workspace-level RDO.

The artifact type of the RDO is set by the DescriptorArtifactTypeID property. The following example demonstrates how to use the property when creating an admin-level RDO:

  • Create a parent object type.
  • Read the object type to get the ArtifactID of the object type.
  • Create the parent RDO with the object type set as the DescriptorArtifactTypeID.
  • Create the object type for the admin-level RDO with the parent object type.
  • Read the object type.
  • Create the RDO with the object type.
public bool Create_RDOWithParent_Workflow(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{
    // Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    try
    {
        // Set the workspace ID to -1 for admin level
        proxy.APIOptions.WorkspaceID = -1;

        // Step 1: Create parent object type
        Client.DTOs.ObjectType parentObjectTypeDTO = new Client.DTOs.ObjectType();
        parentObjectTypeDTO.Name = string.Format("API-ParentOT-{0}", Guid.NewGuid().ToString().Substring(0, 10));
        parentObjectTypeDTO.ParentArtifactTypeID = 1;
        parentObjectTypeDTO.SnapshotAuditingEnabledOnDelete = true;
        parentObjectTypeDTO.Pivot = true;
        parentObjectTypeDTO.Sampling = true;
        parentObjectTypeDTO.PersistentLists = false;
        parentObjectTypeDTO.CopyInstancesOnWorkspaceCreation = false;
        parentObjectTypeDTO.CopyInstancesOnParentCopy = false;

        int parentObjectTypeArtifactID = proxy.Repositories.ObjectType.CreateSingle(parentObjectTypeDTO);
        logger.LogDebug("Parent object type artifactID: {parentObjectTypeArtifactID}", parentObjectTypeArtifactID);

        // Read the object type back to get DescriptorArtifactTypeID
        parentObjectTypeDTO = proxy.Repositories.ObjectType.ReadSingle(parentObjectTypeArtifactID);

        // Step 2: Create parent RDO
        Client.DTOs.RDO parentRDO = new Client.DTOs.RDO();
        parentRDO.ArtifactTypeID = parentObjectTypeDTO.DescriptorArtifactTypeID;
        parentRDO.Fields.Add(new DTOs.FieldValue("Name", string.Format("API-ParentRDO-{0}", Guid.NewGuid().ToString().Substring(0, 10))));
        int parentRDOArtifactID = proxy.Repositories.RDO.CreateSingle(parentRDO);
        logger.LogDebug("Parent RDO artifactID: {parentRDOArtifactID}", parentRDOArtifactID);

        // Step 3: Create object type with parent object type
        Client.DTOs.ObjectType objectType = new Client.DTOs.ObjectType();
        objectType.Name = string.Format("API-OT-{0}", Guid.NewGuid().ToString().Substring(0, 10));
        objectType.ParentArtifactTypeID = parentObjectTypeDTO.DescriptorArtifactTypeID; // Set the parent artifact to the object type created above
        objectType.SnapshotAuditingEnabledOnDelete = true;
        objectType.Pivot = true;
        objectType.Sampling = true;
        objectType.PersistentLists = false;
        objectType.CopyInstancesOnWorkspaceCreation = false;
        objectType.CopyInstancesOnParentCopy = false;
        int objectTypeArtifactID = proxy.Repositories.ObjectType.CreateSingle(objectType);
        logger.LogDebug("Object type artifactID: {objectTypeArtifactID}", objectTypeArtifactID);

        // Read the object type back to get DescriptorArtifactTypeID
        objectType = proxy.Repositories.ObjectType.ReadSingle(objectTypeArtifactID);

        // Step 4: Create RDO with with parent as another RDO
        Client.DTOs.RDO rdo = new Client.DTOs.RDO();
        rdo.ArtifactTypeID = objectType.DescriptorArtifactTypeID;
        rdo.ParentArtifact = new DTOs.Artifact(parentRDOArtifactID); // Set the parent artifact to the RDO created above
        rdo.Fields.Add(new DTOs.FieldValue("Name", string.Format("API-RDO-{0}", Guid.NewGuid().ToString().Substring(0, 10))));
        int rdoArtifactID = proxy.Repositories.RDO.CreateSingle(parentRDO);
        logger.LogDebug("RDO artifactID: {rdoArtifactID}", rdoArtifactID);

        // Clean everything up
        proxy.Repositories.RDO.DeleteSingle(rdoArtifactID);
        proxy.Repositories.ObjectType.DeleteSingle(objectTypeArtifactID);
        proxy.Repositories.RDO.DeleteSingle(parentRDOArtifactID);
        proxy.Repositories.ObjectType.DeleteSingle(parentObjectTypeArtifactID);

        return true;
    }
    catch(Exception ex)
    {
        logger.LogError(ex, "Error creating RDO with parent workflow");
        return false;
    }
}