

Last date modified: April 15 2025
Relativity applications contain system objects and Relativity Dynamic Objects (RDOs). System objects are predefined and included in applications default by default. RDOs are custom objects that you can define for your specific business needs through the UI or programmatically. For information about using objects through the UI, see Relativity Objects .
The Object Manager API provides you with the ability to programmatically work with RDOs and Document objects. It exposes methods for performing the following tasks:
Sample use cases for the Object Manager service include:
You can also use the Object Manager service through REST. However, the REST endpoints do not support cancellation tokens or progress indicators. For more information, see Object Manager (REST).
Note: Object Manager consumers can not exceed 1,000 requests per minute, per web server that the Object Manager is hosted on. For more information, see Rate Limit.
Review the following information to learn about the methods, classes, and exceptions used by the Object Manager service.
Note: The <VersionNumber> variable in the namespace indicates the version number of the API. The version number uses the format uppercase V and an integer version number, such as V1 or V2 in .NET.
The Object Manager API includes the following methods available on the IObjectManager interface in the Relativity.ObjectManager.<VersionNumber>.Interfaces namespace:
The Object Manager API uses the following classes for general functionality. They are available in the Relativity.ObjectManager.<VersionNumber>.Models namespace.
Note: You must set the CallingContext property on one of these objects if you have event handlers that depend on a layout. The event handlers will not function properly if this property is not set. If your event handlers do not require context information, they must then implement the ICanExecuteWithLimitedContext interface available in the Event Handlers API.
In addition, you can use this class to access the following specialized fields when performing a query on a Document object or RDO:
The following table contains a list of fields and their value types. All primitive types are optional, so null is a valid value for them.
FieldType | Expected value type |
---|---|
Fixed-Length Text | string |
Long Text | string |
Date | DateTime |
Whole Number | int? |
Decimal | decimal? |
Currency | decimal? |
Yes/No | bool? |
Single Choice | ChoiceRef |
Multiple Choice | IEnumerable<ChoiceRef> |
User | User (The ArtifactID must be set on this object.) |
File | FileRef |
Single Object | RelativityObjectRef |
Multiple Object | IEnumerable<RelativityObjectRef> |
The following table contains a list of fields and their value types. All primitive types are optional, so null is a valid value for them.
FieldType | Expected value type |
---|---|
Fixed-Length Text | string |
Long Text | string |
Date | DateTime |
Whole Number | int? |
Decimal | decimal? |
Currency | decimal? |
Yes/No | bool? |
Single Choice | Choice |
Multiple Choice | List<Choice> |
User | UserRef |
File | FileRef |
Single Object | RelativityObjectValue |
Multiple Object | List<RelativityObjectValue> |
Note: You can reference RelativityObject objects and FieldValuePair objects by GUID instead of Artifact ID during update and read operations.
The Object Manager API uses the following class for retrieving dependency lists. It is available in the Relativity.ObjectManager.<VersionNumber>.Models namespace.
The Object Manager API uses the following classes for mass operations. They are available in the Relativity.ObjectManager.<VersionNumber>.Models namespace.
The Object Manager API uses the following class for working with hydrated objects. They are available in the Relativity.ObjectManager.<VersionNumber>.Extensions namespace.
For example, you can use the ToRef() method on one of these classes to convert a fully hydrated object to a ref class. This ref class can then be used when instantiating a request object. Each of the following classes have a ToRef() method:
The Object Manager API uses the following class for export operations. It is available in the Relativity.ObjectManager.<VersionNumber>.Models namespace.
The Object Manager service throws several different exception types as follows:
Use the following guidelines when working with the Object Manager service:
The Object Manager has a set rate limit of 1,000 requests per minute, per web server. Exceeding this limit will result in a 429 Too many Requests error message.
In order for the application to successfully handle the Object Manager’s rate limit, the application must:
Note: If the latest version of Relativity.Kepler.Client.SDK is not referenced, you will not be able to reference theTooManyRequestsException type.
In the following code sample, the Object Manager call goes through a retry wrapper that checks the TooManyRequestsException, and uses the ex.Delta value to determine how long to wait before trying again.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public async Task<QueryResultSlim> ExecuteObjectManagerQuerySlim(QueryRequest request)
{
QueryResultSlim response;
int workspaceID = Helper.GetActiveCaseID();
int start = 0;
int length = 25;
using (IObjectManager omProxy = Helper.GetServicesManager().CreateProxy<IObjectManager>(Relativity.API.ExecutionIdentity.System))
{
// Wrap the call to Object Manager in a retry loop that will retry up to 3 times if a TooManyRequestsException is thrown.
response = await RetryIfTooManyRequests(async () => await omProxy.QuerySlimAsync(workspaceID, request, start, length));
}
return response;
}
private async Task<T> RetryIfTooManyRequests<T>(Func<Task<T>> func)
{
int retryLimit = 3;
int retries = 0;
Exception exception = null;
// This is a retry loop that will retry up to 3 times if a TooManyRequestsException is thrown.
// If more than 3 retries are needed, the most recent exception will be thrown.
while (retries < retryLimit)
{
try
{
return await func();
}
catch (TooManyRequestsException ex)
{
await Task.Delay(ex.Delta.Value); // The Delta property tells you how long to wait before retrying.
exception = ex;
retries++;
}
}
throw exception;
}
To test if the application is handling the 429 Too many Requests response correctly, complete the following steps:
Set the application to exceed 1,000 request a minute.
Note: To remove all configuration values set RateLimitConfiguration to an empty string. Deleting an instance setting will leave the last value as the current setting until the process restarts.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Test]
public async Task ExecuteObjectManagerQuerySlim_RetriesThreeTimes_On_TooManyRequestsException()
{
// Arrange
RetryConditionHeaderValue retry = new RetryConditionHeaderValue(new TimeSpan(0, 0, 0, 0, 100));
var objectManager = Substitute.For<IObjectManager>();
objectManager.QuerySlimAsync(Arg.Any<int>(), Arg.Any<QueryRequest>(), Arg.Any<int>(), Arg.Any<int>())
.Throws(x => throw new TooManyRequestsException(retry, "API limit exceeded."));
var servicesManager = Substitute.For<IServicesMgr>();
servicesManager.CreateProxy<IObjectManager>(ExecutionIdentity.System).Returns(objectManager);
var helper = Substitute.For<IEHHelper>();
helper.GetServicesManager().Returns(servicesManager);
helper.GetActiveCaseID().Returns(1234567);
var sut = new TestPreSaveEventHandler(helper);
// Act & Assert
Assert.ThrowsAsync<TooManyRequestsException>(async () => await sut.ExecuteObjectManagerQuerySlim(new QueryRequest()));
await objectManager.Received(3).QuerySlimAsync(Arg.Any<int>(), Arg.Any<QueryRequest>(), Arg.Any<int>(), Arg.Any<int>());
}
Use tokens when you are reading or querying on long text fields, and then later performing an update operation on the returned values. This best practice ensures that a long text field is not inadvertently truncated when performing these operations. You can use the default behavior for other operations, such as displaying data in a grid.
To use tokenized behavior, call the read or query methods as follows:
The following information is provided about the ReadOptions and QueryRequest classes to further explain the properties for long text fields.
The ReadOptions class includes the following properties for long text fields:
The LongTextBehavior enumeration includes the following values:
When this property is not set, the value in the MaximumNumberOfCharactersSupportedByLongText instance setting determines the maximum length. The default value for the instance setting is 100,000 characters. For more information, see
The Object Manager service currently does not support retrieving all the text in a long text field for a read operation when it exceeds the maximum length except through the use of tokens or streaming. For information on the streaming API to retrieve all the data stored in a long text field, see Stream text.
The QueryRequest class includes the following properties for long text fields:
The LongTextBehavior enumeration includes the following values:
If you set the MaxCharactersForLongTextValues property on the QueryRequest object, it determines the maximum number of characters by overriding limit set by the MaximumNumberOfCharactersSupportedByLongText instance setting up to up to the maximum of 1000. When a long text field exceeds maximum number of characters allowed, the default behavior truncates the field.
The Object Manager service currently does not support retrieving all the text in a long text field for a query operation when it exceeds the maximum length except through the use of tokens or streaming. For information on the streaming API to retrieve all the data stored in a long text field, see Stream text.
You can create an IObjectManager instance through a ServiceFactory instance or the Relativity API Helpers. If you want to access the service from a custom page or event handler, use the Relativity API Helpers. For more information, see Relativity API Helpers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//Creates and initializes a ServiceFactory instance.
public void InitializeServiceFactory()
{
String restServerAddress = "http://localhost/relativity.rest/api";
Uri keplerUri = new Uri(restServerAddress);
Relativity.Services.ServiceProxy.ServiceFactorySettings settings = new Relativity.Services.ServiceProxy.ServiceFactorySettings(
keplerUri, new Relativity.Services.ServiceProxy.UsernamePasswordCredentials("ExampleUsername.com", "ExamplePassword1!"));
_serviceFactory = new Relativity.Services.ServiceProxy.ServiceFactory(settings);
}
//Creates an IObjectManager instance through the ServiceFactory instance.
public async Task PerformWorkWithObjectManager()
{
using (IObjectManager objectManager = _serviceFactory.CreateProxy<IObjectManager>())
{
// Do work with the objectManager instance.
}
}
//Creates an IObjectManager instance through the Relativity API Helpers.
public async Task PerformWorkWithConnectionHelperObjectManager()
{
var serviceManager = ConnectionHelper.Helper().GetServicesManager();
using (IObjectManager objectManager = serviceManager.CreateProxy<IObjectManager>(Relativity.API.ExecutionIdentity.System))
{
// Do work with the objectManager instance.
}
}
The Object Manager API supports create, read, update, delete, and query operations on the following field types:
For file field, the Object Manager API supports read, delete, and query operations. To update file fields, follow the workflow described in the File Field Manager Service.
The Object Manager service updates fields on a Document object, which are enabled for propagation. It also updates the enabled fields on all Document objects related to this initially updated object.
The Object Manager API supports interacting with event handlers. Review the following guidelines for using the Object Manager API in event handlers. For more information, see Event Handlers.
Create | Mass create | Read | Query/QuerySlim/Export | Update | Mass update | Delete | Mass delete | Dependency report | |
---|---|---|---|---|---|---|---|---|---|
PreLoad | X | X | X | X | X | X | X | X | |
PreSave | X | X | X | X | X | X | X | ||
PostSave | X | X | X | X | X | X | X | ||
PreDelete | X | X | X | X | X | X | X | ||
PreCascadeDelete | X | X | X | X | X | X | X | ||
PreMassDelete | X | X | X | X | X | X | X |
Note: The Object Manager service rethrows an event handler exception as EventHandlerFailedException. For more information, see Object Manager (.NET).
By default, PreLoad, PreSave, and PostSave event handlers only trigger if the appropriate Create, Read, or Update operation is provided with a CallingContext. If a developer wants their EventHandler to fire when no CallingContext information is provided, they can implement the ICanExecuteWithLimitedContext interface on their EventHandler class. This signals to the Object Manager service that the EventHandlers are safe to run regardless of whether a context is provided.
When an EventHandler that has implemented ICanExecuteWithLimitedContext is invoked without CallingContext, the following context-related properties on the EventHandler class are impacted:
For more information about event handlers, see Develop object type event handlers.
You can access FieldValuePair objects returned from a read or query operation by using the indexers on the RelativityObject class. The indexers consume either the GUID, Artifact ID, or Name of a Field object. They then use the specified identifier for a Field to return the corresponding FieldValuePair object.
The following sample code illustrates how to use an indexer to access a FieldValuePair object returned in the results from a read operation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public async Task<Relativity.ObjectManager.{versionNumber}.Models.FieldValuePair> ReadField(IHelper helper, int workspaceId, int objectArtifactID, string fieldName)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var readRequest = new ReadRequest
{
Object = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID },
Fields = new List<Relativity.ObjectManager.{versionNumber}.Models.FieldRef> { new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { Name = fieldName } }
};
Relativity.ObjectManager.{versionNumber}.Models.ReadResult result = await objectManager.ReadAsync(workspaceId, readRequest);
return result.Object[fieldName];
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object or Fields are not valid for reading.");
}
}
return null;
}
Use the CreateAsync() method to create an RDO with the values set for the existing fields on it. You call this method by passing the following parameters:
Note: If you do not specify a parent object, Relativity defaults to the System object as the parent.
Note: You must set the CallingContext property on OperationOptions object if you have event handlers that depend on a layout. The event handlers will not function properly when this property is not set. If your event handlers do not require context information, they must then implement the ICanExecuteWithLimitedContext interface available in the Event Handlers API.
The following code sample illustrates the information that you need to provide to create an RDO, and to set a group of specified fields.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public async Task<Relativity.ObjectManager.{versionNumber}.Models.CreateResult> Create(IHelper helper, int workspaceID, int objectTypeID, IEnumerable<Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair> fieldValuePairs)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var createRequest = new Relativity.ObjectManager.{versionNumber}.Models.CreateRequest();
createRequest.ObjectType = new Relativity.ObjectManager.{versionNumber}.Models.ObjectTypeRef { ArtifactTypeID = objectTypeID }; //this sets the object type of the RDO you are creating
createRequest.ParentObject = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = SampleWorkspaceRootFolderID }; //the parent of the artifact only needs to be specified if the parent is not system
createRequest.FieldValues = fieldValuePairs;
var callingContext = new Relativity.ObjectManager.{versionNumber}.Models.CallingContext //this sets up a calling context to provide any additional information eventhandlers may need
{
Layout = new Relativity.ObjectManager.{versionNumber}.Models.LayoutRef { ArtifactID = SampleLayoutID },
PageMode = Relativity.ObjectManager.{versionNumber}.Models.PageMode.Edit
};
var createOptions = new Relativity.ObjectManager.{versionNumber}.Models.OperationOptions
{
CallingContext = callingContext
};
return await objectManager.CreateAsync(workspaceID, createRequest, createOptions);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object could not be created.");
}
}
return null;
}
You can mass create multiple RDOs of the same type, and you can specify the values set on the fields that they contain.
Note: If you specify an identifier that is already in the database, an exception will not be thrown. Instead, the Success property on the MassCreateResult object is set to false. Always check the value of the Success property on the results object as a best practice.
To mass create RDOs, pass a MassCreateRequest object as an argument to the CreateAsync() method. This object contains properties for the parent object type, the object type that you are creating, the fields to set, and the values to use for this purpose.
Note: If you do not specify a parent object, Relativity defaults to the System object as the parent.
The overloaded CreateAsync() method supports progress reporting, and cancellation requests for mass update operations. See the following code sample.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public async Task<Relativity.ObjectManager.{versionNumber}.Models.MassCreateResult> MassCreate(IHelper helper, int workspaceID, int objectTypeID, IReadOnlyList<Relativity.ObjectManager.{versionNumber}.Models.FieldRef> fields, IReadOnlyList<IReadOnlyList<object>> fieldValues)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var massCreateRequest = new Relativity.ObjectManager.{versionNumber}.Models.MassCreateRequest();
// Sets the object type of the RDO that you you want to create.
massCreateRequest.ObjectType = new Relativity.ObjectManager.{versionNumber}.Models.ObjectTypeRef { ArtifactTypeID = objectTypeID };
// Sets the fields to populate.
massCreateRequest.Fields = fields;
// Sets the values in the order that the fields provided.
massCreateRequest.ValueLists = fieldValues;
return await objectManager.CreateAsync(workspaceID, massCreateRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object could not be created.");
}
}
return null;
}
Use the ReadAsync() method to retrieve the field values on a Document object or RDO. The method returns fields that you can add to a layout in your custom application.
You call this method by passing the required combination of the following parameters:
The following list highlights key properties on the ReadOptions class, and suggested setting for them:
You must set the CallingContext property on ReadOptions or OperationOptions object if you have event handlers that depend on a layout. The event handlers will not function properly when this property is not set. If your event handlers do not require context information, they must then implement the ICanExecuteWithLimitedContext interface available in the Event Handlers API.
The following code sample illustrates how to read a specified subset of fields.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public async Task<Relativity.ObjectManager.{versionNumber}.Models.ReadResult> ReadPartial(IHelper helper, int workspaceID, int objectArtifactID, IEnumerable<Relativity.ObjectManager.{versionNumber}.Models.FieldRef> fieldRefs)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var readRequest = new Relativity.ObjectManager.{versionNumber}.Models.ReadRequest
{
Object = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID },
Fields = fieldRefs
};
return await objectManager.ReadAsync(workspaceID, readRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object or Fields are not valid for reading.");
}
}
return null;
}
Use the UpdateAsync() method to modify a field on a Document object or RDO. You call this method by passing the following parameters:
Note: You must set the CallingContext property on UpdateOptions object if you have event handlers that depend on a layout. The event handlers will not function properly when this property is not set. If your event handlers do not require context information, they must then implement the ICanExecuteWithLimitedContext interface available in the Event Handlers API.
The following code samples illustrates how to update field values on a single Document object or RDO. The process for updating other field types is like that used for updating a single object:
Note: If you need to update a long text field that exceeds the length limits of an HTTP request, use the UpdateLongTextFromStreamAsync() method. For more information, see Update field values on a multiple object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public async Task<Relativity.ObjectManager.{versionNumber}.Models.UpdateResult> UpdateSingleSingleObject(IHelper helper, int workspaceID, int objectArtifactID, int fieldArtifactID, int singleObjectArtifactID)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var relativityObject = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID };
var fieldValuePair = new Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair
{
Field = new Relativity.ObjectManager.{versionNumber}.Models.FieldRef() { ArtifactID = fieldArtifactID },
Value = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = singleObjectArtifactID }
};
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.UpdateRequest
{
Object = relativityObject,
FieldValues = new List<Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair> { fieldValuePair }
};
return await objectManager.UpdateAsync(workspaceID, updateRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
To updates field values on a multiple object or choice, you follow many of the same steps as those for updating a single object. You can also optionally specify the update behavior on the UpdateOptions object, which is passed to the UpdateAync() method. The FieldUpdateBehavior enumeration is used to specify this behavior. It includes the following options:
This behavior is now set for the entire update operation. If you do not pass a UpdateOptions instance to this method, the service replaces the values by default.
Note: The update operation for field values on a multiple object works the same way on a multiple choice field.
The following code sample illustrates how to call the UpdateSync()method without passing an UpdateOptions instance to it. Since this code does not specify the update behavior, the field values are replaced by default.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public async Task<Relativity.ObjectManager.{versionNumber}.Models.UpdateResult> UpdateSingleMultipleObject(IHelper helper, int workspaceID, int objectArtifactID, int fieldArtifactID, IEnumerable<Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef> objects)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var relativityObject = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID };
var fieldValuePair = new Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair
{
Field = new Relativity.ObjectManager.{versionNumber}.Models.FieldRef() { ArtifactID = fieldArtifactID },
Value = objects
};
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.UpdateRequest
{
Object = relativityObject,
FieldValues = new List<Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair> { fieldValuePair }
};
return await objectManager.UpdateAsync(workspaceID, updateRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
The following code sample illustrates how to specify the update behavior by passing an UpdateOptions instance to the UpdateAsync() method. In this sample, the UpdateBehavior property is set to Merge. You also have the option to set this property to Replace.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public async Task<Relativity.ObjectManager.{versionNumber}.Models.UpdateResult> UpdateSingleMultipleObjectWithOptions(IHelper helper, int workspaceID, int objectArtifactID, int fieldArtifactID, IEnumerable<Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef> objects)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var relativityObject = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID };
var fieldValuePair = new Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair
{
Field = new Relativity.ObjectManager.{versionNumber}.Models.FieldRef() { ArtifactID = fieldArtifactID },
Value = objects
};
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.UpdateRequest
{
Object = relativityObject,
FieldValues = new List<Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair> { fieldValuePair }
};
var updateOptions = new Relativity.ObjectManager.{versionNumber}.Models.UpdateOptions
{
UpdateBehavior = Relativity.ObjectManager.{versionNumber}.Models.FieldUpdateBehavior.Merge
};
return await objectManager.UpdateAsync(workspaceID, updateRequest, updateOptions);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
You can use the UpdateLongTextFromStreamAsync() method to update a single long text field that exceeds the length limits of an HTTP request. This method does not trigger an event handler.
Note: You can use the UpdateAsync() method to update a single long text field with a length less than the HTTP request limits. For more information, see Update field values on a single object.
The following code sample illustrates how to instantiate the UpdateLongTextFromStreamRequest object and required stream objects. It then shows how to pass the workspace ID and these objects to the UpdateLongTextFromStreamAsync() method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public async Task<Relativity.ObjectManager.{versionNumber}.Models.UpdateResult> UpdateLongTextFromStream(IHelper helper, int workspaceID, int objectArtifactID, string valueToSet)
{
Guid kGuidForExtractedTextField = new Guid("58D35076-1B1D-43B4-BFF4-D6C089DE51B2");
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
var relativityObject = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef
{
ArtifactID = objectArtifactID
};
var extractedTextFieldRef = new Relativity.ObjectManager.{versionNumber}.Models.FieldRef
{
Guid = kGuidForExtractedTextField
};
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.UpdateLongTextFromStreamRequest
{
Object = relativityObject,
Field = extractedTextFieldRef
};
try
{
using (var memoryStream = new System.IO.MemoryStream())
{
using (var streamWriter = new System.IO.StreamWriter(memoryStream, new System.Text.UnicodeEncoding()))
{
streamWriter.Write(valueToSet);
streamWriter.Flush();
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
using (var keplerStream = new Relativity.Kepler.Transport.KeplerStream(memoryStream))
{
await objectManager.UpdateLongTextFromStreamAsync(workspaceID, updateRequest, keplerStream).ConfigureAwait(false);
}
}
}
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
Use the overloaded UpdateAsync() method to mass update RDOs. You can mass update Document objects or RDOs in the following ways:
Similar to updating a single object, the overloaded UpdateAsync() method supports progress reporting, and cancellation requests for mass update operations.
Review the following best practices for mass update operations:
The following code sample illustrates how to set the ObjectIdentificationCriteria property on the MassUpdateByCriteriaRequest object to mass update objects based on search conditions. For searching information, see Query for resources.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task<Relativity.ObjectManager.{versionNumber}.Models.MassUpdateResult> MassUpdate(IHelper helper, int workspaceID, Relativity.ObjectManager.{versionNumber}.Models.ObjectIdentificationCriteria criteria, IEnumerable<Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair> fieldRefValuePairs, Relativity.ObjectManager.{versionNumber}.Models.FieldUpdateBehavior behavior)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.MassUpdateByCriteriaRequest();
// Run a query for all the items that you want to update.
updateRequest.ObjectIdentificationCriteria = criteria;
// Indicate the fields and the values to be set for all the objects provided.
updateRequest.FieldValues = fieldRefValuePairs;
var updateOptions = new Relativity.ObjectManager.{versionNumber}.Models.MassUpdateOptions();
// By default, the behavior is replace.
updateOptions.UpdateBehavior = behavior;
return await objectManager.UpdateAsync(workspaceID, updateRequest, updateOptions);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
The following code sample illustrates how to set theMassUpdateByObjectIdentifiersRequest object to mass update Document objects or RDOs based on a list of RelativityObjectRef instances. The RelativityObjectRef class has properties for the Artifact ID and GUID that you can use to reference an object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task<Relativity.ObjectManager.{versionNumber}.Models.MassUpdateResult> MassUpdate(IHelper helper, int workspaceID, IReadOnlyList<Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef> relativityObjectRefs, IEnumerable<Relativity.ObjectManager.{versionNumber}.Models.FieldRefValuePair> fieldRefValuePairs, Relativity.ObjectManager.{versionNumber}.Models.FieldUpdateBehavior behavior)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.MassUpdateByObjectIdentifiersRequest();
// Represents RelativityObjects to update.
updateRequest.Objects = relativityObjectRefs;
// Indicates the fields and the values to be set for all the objects provided.
updateRequest.FieldValues = fieldRefValuePairs;
var updateOptions = new Relativity.ObjectManager.{versionNumber}.Models.MassUpdateOptions();
// By default, the behavior is replace.
updateOptions.UpdateBehavior = behavior;
return await objectManager.UpdateAsync(workspaceID, updateRequest, updateOptions);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
The following code sample illustrates how to set the Fields and ObjectValues properties on a MassUpdatePerObjectsRequest object. This object is used to mass update Document objects or RDOs by setting different values for specific fields on a group of objects. The fields variable references the list of fields for updating, and the objectRefValuesPairs variable is a combination of the RelativityObjects to be updated and the values used for this purpose. The values must be provided in the same order as the fields that they are used to update.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public async Task<Relativity.ObjectManager.{versionNumber}.Models.MassUpdateResult> MassUpdate(IHelper helper, int workspaceID, IReadOnlyList<Relativity.ObjectManager.{versionNumber}.Models.FieldRef> fields, IReadOnlyList<Relativity.ObjectManager.{versionNumber}.Models.ObjectRefValuesPair> objectRefValuesPairs, Relativity.ObjectManager.{versionNumber}.Models.FieldUpdateBehavior behavior)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var updateRequest = new Relativity.ObjectManager.{versionNumber}.Models.MassUpdatePerObjectsRequest();
// The fields updated on each of the objects in the list.
updateRequest.Fields = fields;
// The RelativityObjects and the values to be set for all the fields provided.
updateRequest.ObjectValues = objectRefValuesPairs;
var updateOptions = new Relativity.ObjectManager.{versionNumber}.Models.MassUpdateOptions();
// The default behavior is replace.
updateOptions.UpdateBehavior = behavior;
return await objectManager.UpdateAsync(workspaceID, updateRequest, updateOptions);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object is not valid for updating.");
}
}
return null;
}
The GetDependencyListAsync() method retrieves information about Relativity objects dependent on one or more specific objects selected for deletion. It returns a list of Dependency objects, which contain information such as the relationship between the objects and whether a dependent object would be deleted or unlinked. For more information on the dependency report available through the Relativity UI, see Deleting object dependencies.
Sample use cases for this method include:
Use these guidelines for calling the GetDependencyListAsync() method:
The following code sample illustrates how to instantiate a DependencyListByObjectIdentifiersRequest object and set its Object property to a list of RelativityObjectRef instances. It then calls the GetDependencyListAsync() method by passing it the Artifact ID of the workspace, and the request object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public async Task<List<Relativity.Shared.{versionNumber}.Models.Dependency>> GetDependencyList(IHelper helper, int workspaceID, int objectArtifactID)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var dependencyRequest = new Relativity.ObjectManager.{versionNumber}.Models.DependencyListByObjectIdentifiersRequest();
dependencyRequest.Objects = new List<Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef>
{
new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID }
};
return await objectManager.GetDependencyListAsync(workspaceID, dependencyRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "Dependencies for the Relativity Object could not be retrieved.");
}
return null;
}
}
Use the DeleteAsync() method to remove Document objects and all their associated files, and RDOs from Relativity. You call this method by passing the following parameters:
If you use the overloaded DeleteAsync() method, you can also pass the following arguments:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public async Task<Relativity.ObjectManager.{versionNumber}.Models.DeleteResult> Delete(IHelper helper, int workspaceID, int objectArtifactID)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var deleteRequest = new Relativity.ObjectManager.{versionNumber}.Models.DeleteRequest();
deleteRequest.Object = new Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef { ArtifactID = objectArtifactID };
return await objectManager.DeleteAsync(workspaceID, deleteRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object could not be deleted.");
}
return null;
}
}
Note: You should use the Mass Operations API to mass-delete Document objects or RDOs, instead of using the DeleteAsync() method described here.
You can use the overloaded DeleteAsync() method to mass delete Document objects or RDOs. All the objects in a mass delete operation must be the same type. Additionally, you can mass delete these objects in the following ways:
The overloaded DeleteAsync() method supports progress reporting, and cancellation requests for mass delete operations.
The following code sample illustrates how to set the ObjectIdentificationCriteria property on the MassDeleteByCriteriaRequest object to mass delete objects based on search conditions. For more information, see Query for resources.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public async Task<Relativity.ObjectManager.{versionNumber}.Models.MassDeleteResult> MassDelete(IHelper helper, int workspaceID, Relativity.ObjectManager.{versionNumber}.Models.ObjectIdentificationCriteria criteria)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var deleteRequest = new Relativity.ObjectManager.{versionNumber}.Models.MassDeleteByCriteriaRequest();
// Run a query for all the items that you want to delete.
deleteRequest.ObjectIdentificationCriteria = criteria;
return await objectManager.DeleteAsync(workspaceID, deleteRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object could not be deleted.");
}
return null;
}
}
The following code sample illustrates how to set the Objects property on the MassDeleteByObjectIdentifiersRequest object to mass delete Document objects or RDOs based on a list of RelativityObjectRef instances. The RelativityObjectRef class has properties for the Artifact ID and GUID that you can use to reference an object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public async Task<Relativity.ObjectManager.{versionNumber}.Models.MassDeleteResult> MassDelete(IHelper helper, int workspaceID, IReadOnlyList<Relativity.ObjectManager.{versionNumber}.Models.RelativityObjectRef> relativityObjectRefs)
{
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
try
{
var deleteRequest = new Relativity.ObjectManager.{versionNumber}.Models.MassDeleteByObjectIdentifiersRequest();
// Represents a list of RelativityObjects to be deleted.
deleteRequest.Objects = relativityObjectRefs;
return await objectManager.DeleteAsync(workspaceID, deleteRequest);
}
catch (ValidationException exception)
{
_logger.LogError(exception, "The Relativity Object could not be deleted.");
}
return null;
}
}
With the Object Manager service, you can query for Workspaces, Documents, RDOs, and system types. This service includes the QueryAsync() method, which returns detailed information about the field-value pairs returned by the query. The QuerySlimAsync() method returns a smaller payload, which saves bandwidth. This method is useful for mobile devices and for displaying tabular data.
Note: The Query endpoints are capable of reading data that is being updated in a separate, not-yet-committed database transaction. Utilize the Read endpoint if you want to wait for all in-flight transactions to complete before data is returned.
Call the QueryAsync() or QuerySlimAsync() method the by passing the following parameters:
Note: To search for data, you can use a variety of query options, including conditions, fields, sorts, and relational fields. These query options have a specific syntax for defining the for defining query conditions. For information about query conditions and options, see Query for resources.
1
2
3
4
Fields = new List<FieldRef>()
{
new FieldRef{ Name = "*"}
}
If you use one of the overloaded methods, you can also pass the following arguments:
The following code samples illustrate how to run a query for Document objects using the Object Manager service. They illustrate how to define the query, call the QueryAsync() method, and return a QueryResult object containing the search results.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public async Task<Relativity.ObjectManager.{versionNumber}.Models.QueryResult> QueryAsync(IHelper helper, int workspaceID)
{
try
{
//Prepare parameters for query call
const int documentArtifactTypeID = 10; //target artifact type to query (Document is always 10)
const int indexOfFirstDocumentInResult = 1; //1-based index of first document in query results to retrieve
const int lengthOfResults = 100; //max number of results to return in this query call.
var sort = new Relativity.ObjectManager.{versionNumber}.Models.Sort()
{
Direction = Relativity.ObjectManager.{versionNumber}.Models.SortEnum.Ascending,
FieldIdentifier = new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = this.SampleField_FixedLengthText_ID }
};
var queryRequest = new Relativity.ObjectManager.{versionNumber}.Models.QueryRequest()
{
ObjectType = new Relativity.ObjectManager.{versionNumber}.Models.ObjectTypeRef { ArtifactTypeID = documentArtifactTypeID },
Condition = "('Email From' IN ['Test0@Test.com','Test1@Test.com'])", //query condition syntax is used to build query condtion. See Relativity's developer documentation for more details
Fields = new List<Relativity.ObjectManager.{versionNumber}.Models.FieldRef>() //array of fields to return. ArtifactId will always be returned.
{
new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = SampleField_FixedLengthText_ID },
new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = SampleChoice_ID },
new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = SampleField_MultiObject_ID }
},
IncludeIDWindow = false,
RelationalField = null, //name of relational field to expand query results to related objects
SampleParameters = null,
SearchProviderCondition = null, //see documentation on building search providers
Sorts = new List<Relativity.ObjectManager.{versionNumber}.Models.Sort> { sort }, //an array of Fields with sorting order
QueryHint = "waitfor:5"
};
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.CurrentUser))
{
return await objectManager.QueryAsync(workspaceID, queryRequest, indexOfFirstDocumentInResult, lengthOfResults);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error: ObjectManager.QueryAsync was not successful");
}
return null;
}
Code sample for QuerySlimAsync() method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public async Task<Relativity.ObjectManager.{versionNumber}.Models.QueryResultSlim> QuerySlimAsync(IHelper helper, int workspaceID)
{
try
{
//Prepare parameters for query call
const int documentArtifactTypeId = 10; //target artifact type to query (Document is always 10)
const int indexOfFirstDocumentInResult = 1; //1-based index of first document in query results to retrieve
const int lengthOfResults = 100; //max number of results to return in this query call.
var sort = new Relativity.ObjectManager.{versionNumber}.Models.Sort()
{
Direction = Relativity.ObjectManager.{versionNumber}.Models.SortEnum.Ascending,
FieldIdentifier = new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = this.SampleField_FixedLengthText_ID }
};
var queryRequest = new Relativity.ObjectManager.{versionNumber}.Models.QueryRequest()
{
ObjectType = new Relativity.ObjectManager.{versionNumber}.Models.ObjectTypeRef { ArtifactTypeID = documentArtifactTypeId },
Condition = "('Email From' IN ['Test0@Test.com','Test1@Test.com'])", //query condition syntax is used to build query condtion. See Relativity's developer documentation for more details
Fields = new List<Relativity.ObjectManager.{versionNumber}.Models.FieldRef>() //array of fields to return. ArtifactId will always be returned.
{
new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = SampleField_FixedLengthText_ID },
new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = SampleChoice_ID },
new Relativity.ObjectManager.{versionNumber}.Models.FieldRef { ArtifactID = SampleField_MultiObject_ID }
},
IncludeIDWindow = false,
RelationalField = null, //name of relational field to expand query results to related objects
SampleParameters = null,
SearchProviderCondition = null, //see documentation on building search providers
Sorts = new List<Relativity.ObjectManager.{versionNumber}.Models.Sort> { sort }, //an array of Fields with sorting order
QueryHint = "waitfor:5"
};
using (IObjectManager objectManager = helper.GetServicesManager().CreateProxy<IObjectManager>(ExecutionIdentity.System))
{
return await objectManager.QuerySlimAsync(workspaceID, queryRequest, indexOfFirstDocumentInResult, lengthOfResults);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error: ObjectManager.QueryAsync was not successful");
}
return null;
}
The Object Manager API supports exporting document fields, including complete long text fields such as extracted text, via a set of endpoints collectively called the Export API. This export functionality differs in the following ways from the standard document access performed by the Object Manager API:
See the following subsections for more information:
The export process is multiple step workflow that uses several methods on the IObjectManager interface:
For an example of this workflow, see Export API code sample.
Use the InitializeExportAsync() method to set up the export of documents from a workspace based on a query. You call this method by passing the following parameters:
queryRequest - the query that defines the data set to export, including ObjectType and Fields, query condition, and an optional maximum text length to export inline. For more information, see Query for Relativity objects.
You can use the MaxCharactersForLongTextValues field of the queryRequest object to override the number limit set by the MaximumLongTextSizeForExportInCell instance setting. For more information, see
The semantics of MaxCharactersForLongTextValues field is slightly different than other Object Manager API uses:
This method returns an instance of ExportInitializationResults class, which contains the following:
Note: After an export job is initialized, the export RunID only valid for seven days. The export job then expires and is no longer available for retrieving blocks of documents.
For the complete code, see Export API code sample.
1
2
ExportInitializationResults exportInitializationResults =
objectManager.InitializeExportAsync(workspaceId, queryRequest, 0).Result;
Call one of the following methods to retrieve document fields from the export job:
Review the following considerations for these methods:
Use the RetrieveNextResultsBlockFromExportAsync() method to get the next block of records from an in-progress export job. You call this method by passing the following parameters:
The returned RelativityObjectSlim array contains the data for multiple documents, up to and including batchSize. The fields for each document appear in the order defined in the QueryRequest object during initialization.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Get blocks of documents until none are left.
RelativityObjectSlim[] currentBlock = null;
bool done = false;
while (!done)
{
try
{
currentBlock = objectManager.RetrieveNextResultsBlockFromExportAsync(workspaceId, runId, blockSize).Result;
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return;
}
if (currentBlock == null || !currentBlock.Any())
{
done = true;
break;
}
Console.WriteLine("Got block of " + currentBlock.Count() + " documents");
Console.WriteLine();
Use the RetrieveResultsBlockFromExportAsync() method to get a specific block of records from an in-progress export job. You call this method by passing the following parameters:
Note: The actual number of results returned may be less than the maximum number requested.
The returned RelativityObjectSlim array contains the data for multiple documents, up to and including the resultsBlockSize, or it may include less the maximum number requested. The fields for each document appear in the order defined in the QueryRequest object during export initialization.
1
2
3
4
5
6
7
8
9
10
11
12
13
ExportInitializationResults exportInitResults = await objectManager.InitializeExportAsync(workspaceArtifactID, queryRequest, 0).ConfigureAwait(false);
Guid exportID = exportInitResults.RunID;
int totalNumberOfRecords = exportInitResults.RecordCount;
int exportIndexID = 0;
int resultsBlockSize = totalNumberOfRecords;
RelativityObjectSlim[] currentBlock = await objectManager.RetrieveResultsBlockFromExportAsync(workspaceArtifactID, exportID, resultsBlockSize, exportIndexID).ConfigureAwait(false);
exportIndexID += currentBlock.Length;
resultsBlockSize -= currentBlock.Length;
return currentBlock;
Use the StreamLongTextAsync() method to retrieve a stream of text for long text fields marked as exceeding the size limit for the data returned by the RetrieveNextResultsBlockFromExportAsync() or the RetrieveResultsBlockFromExportAsync() method. For more information, see Retrieve objects.
You call the StreamLongTextAsync() method by passing the following parameters:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Check to determine if the long text field needs to be streamed.
if (longTextIds.Contains(i))
{
if (ros.Values[i].Equals(_SHIBBOLETH))
{
Console.WriteLine("Text is too long, it must be streamed");
Console.WriteLine();
RelativityObjectRef documentObjectRef = new RelativityObjectRef { ArtifactID = ros.ArtifactID };
using (IKeplerStream keplerStream = objectManager.StreamLongTextAsync(workspaceId, documentObjectRef, queryRequest.Fields.ElementAt(i)).Result)
{
using (Stream realStream = keplerStream.GetStreamAsync().Result)
{
StreamReader reader = new StreamReader(realStream, Encoding.Unicode);
String line;
while ((line = reader.ReadLine()) != null)
{
Console.Write(line);
}
Console.WriteLine();
}
}
}
}
The resulting stream is encoded using UTF-16 and begins with a Unicode Byte Order Mark. We recommend that you look for the UTF-8 Byte Order Mark (0xEF,0xBB,0xBF), when one of the two UTF-16 Byte Order Marks (0xFF 0xFE or 0xFE 0xFF) is not found because that encoding may be used in the future.
The Export API code sample illustrates how to export the extracted text fields on Document objects.
Note: When running this code sample, make sure to include the required using statements. For example, the call to call Array.Any() requires a using System.Linq statement.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
using Relativity.Kepler.Transport;
using Relativity.ObjectManager.{versionNumber}.Interfaces;
using Relativity.ObjectManager.{versionNumber}.Models;
using Relativity.Services.ServiceProxy;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace Relativity.Sample
{
class Program
{
// Provide an indicator that the text is not present and needs to be streamed.
private const string _SHIBBOLETH = "#KCURA99DF2F0FEB88420388879F1282A55760#";
// Set the URL for the Relativity instance.
private static Uri relativityUrl = new Uri("https://relativity.mycompany.com");
// Set the ID of the Workspace.
private static int workspaceID = 1234567;
// Provide an Object Manager query.
private static QueryRequest queryRequest = new QueryRequest()
{
Fields = new FieldRef[]
{
new FieldRef {Name = "Control Number"},
new FieldRef {Name = "Extracted Text"}
},
MaxCharactersForLongTextValues = 1024 * 10,
ObjectType = new ObjectTypeRef { ArtifactTypeID = 10 } // Document
};
// Count of the number of documents to return per call to RetrieveNextResultsBlock() method.
private static int blockSize = 1000;
// Provide credentials. Production environments should use a secure credential type.
private static Credentials credentials = new UsernamePasswordCredentials("me@mycompany.com", "Password goes here");
static void Main(string[] args)
{
try
{
// Get an instance of the Object Manager.
IObjectManager objectManager;
try
{
objectManager = GetKeplerServiceFactory(relativityUrl, credentials).CreateProxy<IObjectManager>();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return;
}
// Initialize Export API using the properties set above.
Guid runID;
long recordCount;
List<FieldMetadata> fieldData;
int[] longTextIds;
try
{
ExportInitializationResults exportInitializationResults =
objectManager.InitializeExportAsync(workspaceID, queryRequest, 0).Result;
// Save infomation about this "run".
runID = exportInitializationResults.RunID;
recordCount = exportInitializationResults.RecordCount;
fieldData = exportInitializationResults.FieldData;
// Find indexes of all long text fields.
List<int> longTextIdList = new List<int>();
for (int i = 0; i < exportInitializationResults.FieldData.Count; i++)
{
if (exportInitializationResults.FieldData[i].FieldType == FieldType.LongText)
{
longTextIdList.Add(i);
}
}
longTextIds = longTextIdList.ToArray();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return;
}
Console.WriteLine("RunId " + runID + " will return " + recordCount + " documents");
Console.WriteLine();
// Get blocks of documents until none are left.
RelativityObjectSlim[] currentBlock = null;
bool done = false;
while (!done)
{
try
{
currentBlock = objectManager.RetrieveNextResultsBlockFromExportAsync(workspaceID, runID, blockSize).Result;
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return;
}
if (currentBlock == null || !currentBlock.Any())
{
done = true;
break;
}
Console.WriteLine("Got block of " + currentBlock.Count() + " documents");
Console.WriteLine();
// Print out the fields for each document.
foreach (RelativityObjectSlim ros in currentBlock)
{
for (int i = 0; i < fieldData.Count; i++)
{
Console.WriteLine(fieldData[i].Name + ": " + ros.Values[i]);
// Check to determine if the long text field needs to be streamed.
if (longTextIds.Contains(i))
{
if (ros.Values[i].Equals(_SHIBBOLETH))
{
Console.WriteLine("Text is too long, it must be streamed");
Console.WriteLine();
RelativityObjectRef documentObjectRef = new RelativityObjectRef { ArtifactID = ros.ArtifactID };
using (IKeplerStream keplerStream = objectManager.StreamLongTextAsync(workspaceID, documentObjectRef, queryRequest.Fields.ElementAt(i)).Result)
{
using (Stream realStream = keplerStream.GetStreamAsync().Result)
{
StreamReader reader = new StreamReader(realStream, Encoding.Unicode);
String line;
while ((line = reader.ReadLine()) != null)
{
Console.Write(line);
}
Console.WriteLine();
}
}
}
}
}
Console.WriteLine();
}
Console.WriteLine("Block complete");
Console.WriteLine();
}
Console.WriteLine("All blocks complete");
Console.WriteLine();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return;
}
}
private static ServiceFactory GetKeplerServiceFactory(Uri relativityUrl, Credentials credentials)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.DefaultConnectionLimit = 128;
Uri restUri = new Uri(relativityUrl, "Relativity.REST/api");
Uri servicesUri = new Uri(relativityUrl, "Relativity.REST/api/Relativity.ObjectManager");
ServiceFactorySettings settings = new ServiceFactorySettings(servicesUri, restUri, credentials);
ServiceFactory factory = new ServiceFactory(settings);
return factory;
}
}
}
You can use the Export API in multiple threads to achieve high throughput. To simplify this process, a helper library is available. It also functions as an example illustrating how to run your own concurrent implementation. For more information, see relativitydev/export-api-helper on GitHub.
On this page
Why was this not helpful?
Check one that applies.
Thank you for your feedback.
Want to tell us more?
Great!
Additional Resources |
|||
DevHelp Community | GitHub | Release Notes | NuGet |