InstanceService.GetRelatedInstances
Reference
PagedData<RelatedInstance> GetRelatedInstances(Guid instanceId, RelatedInstanceQuery relatedInstanceQuery)
Use GetRelatedInstances to retrieve instances that are related to a specific instance through defined relationships. This API supports complex filtering, sorting, and pagination of related instances across multiple relationship types and target types.
Parameters
instanceId: The unique identifier of the source instance for which to retrieve related instances.relatedInstanceQuery: Query object containing relationship filters, attribute filters, sorting criteria, and pagination settings.RelationFilters: Array of relationship filters specifying relation type names, target type names, and relationship direction.AttributeFilterExpressions: Optional attribute-based filtering criteria for the related instances.Skip,Take: Pagination parameters for result set.ParentAttributes: Optional array of parent attribute paths to include in the results.GetCountOnly: When true, returns only the total count without actual data items.
Returns
PagedData<RelatedInstance>:
- Collection of RelatedInstance objects representing related entities for the specified instance.
- Each RelatedInstance contains attributes and relationship details.
- Includes pagination metadata (TotalCount, Skip, Take).
- Returns empty collection if no related instances are found.
Error Handling & Caveats
- If the source instance does not exist or the user lacks permission, an AccessDeniedException is thrown.
- If no relation filters are provided, an ArgumentNullException is thrown with localized message "Relation filter required".
- If any relation filter has empty RelationTypeName, an ArgumentNullException is thrown with message "Relation filters invalid - RelationTypeName required".
- If any relation filter has empty TypeName, an ArgumentNullException is thrown with message "Relation filters invalid - TypeName required".
- Performance is optimized through flush mode management and proper database query execution.
- Parent attributes are only populated if explicitly requested in the query.
- Prefer
SafeItems()extension while iterating to avoid manual null checks. - When using StateFilter, ensure the state names match exactly as configured in the lifecycle.
- RelationDirection must be correctly specified (From/To) based on the relationship definition in the schema.
- Always specify appropriate Skip/Take values for large datasets to avoid performance issues.
Usage
using Prorigo.Protrak.API.Contracts.Builders;
using Prorigo.Protrak.API.Contracts.Extensions;
try {
var relatedQuery = RelatedQueryBuilder.Create()
.ForRelation("ReviewerToTask", "Reviewer", RelationDirection.From)
.Select("Name", "Email", "Status")
.InStates("Accepted", "InProgress")
.TakeAll()
.Build();
var reviewers = InstanceService.GetRelatedInstances(taskId, relatedQuery);
foreach (var reviewer in reviewers.SafeItems()) {
Console.WriteLine($"Reviewer: {reviewer.Name}");
}
} catch (ArgumentNullException ex) {
// Handle missing required parameters
} catch (AccessDeniedException ex) {
// Handle permission errors
}
Example: Getting Related Instances with State Filtering
try {
var subscriptionRenewalQuery = RelatedQueryBuilder.Create()
.ForRelation("ServiceToRenewal", "ServiceRenewal", RelationDirection.To)
.Select("StartPeriod", "EndPeriod")
.InStates("PaymentCompleted", "PaymentInProcess")
.TakeAll()
.Build();
var approvedRenewals = InstanceService.GetRelatedInstances(serviceId, subscriptionRenewalQuery);
foreach (var renewal in approvedRenewals.SafeItems()) {
var startPeriod = renewal.GetDateAttributeValue("StartPeriod");
var endPeriod = renewal.GetDateAttributeValue("EndPeriod");
if (startPeriod.HasValue && endPeriod.HasValue) {
Console.WriteLine($"Renewal period: {startPeriod.Value} to {endPeriod.Value}");
}
}
} catch (Exception ex) {
Console.WriteLine($"Error retrieving service renewals: {ex.Message}");
}
Example: Getting Division from Department
try {
var departmentToDivisionQuery = RelatedQueryBuilder.Create()
.ForRelation("DivisionToDepartment", "Division", RelationDirection.From)
.Select("Dean")
.TakeAll()
.Build();
var divisionData = InstanceService.GetRelatedInstances(departmentId, departmentToDivisionQuery);
var division = divisionData.FirstOrDefault();
if (division != null) {
var deanUsers = division.GetUserAttributeValue("Dean");
if (deanUsers.Any()) {
Console.WriteLine($"Dean found: {deanUsers.First().DisplayName}");
} else {
throw new Exception("Dean for related division doesn't exist");
}
}
} catch (Exception ex) {
Console.WriteLine($"Error retrieving division: {ex.Message}");
}
Troubleshooting
- If no results are returned, verify that relationships exist and the user has access to related instances.
- If RelationTypeName validation fails, ensure the relationship type exists and is spelled correctly.
- If TypeName validation fails, verify the target instance type exists in the system.
- For performance issues with large result sets, use pagination (Skip/Take) and consider using GetCountOnly for initial queries.
- If parent attributes are not populated, ensure the ParentAttributes array contains valid attribute paths in the correct format.
- For access control issues, verify user permissions on both source and target instances.
- Prefer
foreach (var item in relatedInstances.SafeItems())over directItemsnull checks. - When using StateFilter, ensure state names match exactly (case-sensitive) as defined in lifecycle configuration.
- If RelationDirection seems incorrect, verify the relationship definition in the schema and use the correct direction (From/To).
- For batch operations, always use
Take = int.MaxValueto ensure all related instances are retrieved. - When accessing specific attributes, always check for null values before using them.