Dom helper class
CRUD methods
The DomHelper
class can be used in a script, protocol, or app to execute create, read, update, and delete (CRUD) actions on DOM objects.
To do so, first call the constructor of the helper, provide a callback to SLNet, and specify a module ID for which module settings have been defined. For example:
var helper = new DomHelper(engine.SendSLNetMessages, "a_module_id");
Note
You will need to add the using Skyline.DataMiner.Net.Apps.DataMinerObjectModel;
statement to include the helper class.
You can then call the Create, Read, Update, or Delete methods on the CRUD helper components of the helper.
Note
When multiple DomInstances
need processing, from DataMiner 10.4.2/10.5.0 onwards, calls are available to do so for up to 100 DomInstances in one go.
For example:
// Create a DomDefinition
var domDefinition = new DomDefinition("DomDefinitionName");
helper.DomDefinitions.Create(domDefinition);
By default, a CrudFailedException
will be thrown if a call fails. However, you can disable this and check if something went wrong yourself by requesting the TraceData
object of the last call. This object contains all errors and warnings. For example:
// Disable the exceptions
helper.DomInstances.ThrowExceptionsOnErrorData = false;
// Do a call
helper.DomInstances.Create(domInstance);
// Get the TraceData and check if the last call succeeded
var traceData = helper.DomInstances.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
// Something went wrong, retrieve all DomInstance errors
var errors = traceData.GetErrorDataOfType<DomInstanceError>();
foreach (var error in errors)
{
// Do something with the error, e.g. log it
engine.GenerateInformation($"Error reason: {error.ErrorReason}");
}
// You can also just log the complete TraceData object,
// this will clearly show the errors, reasons and extra info
engine.GenerateInformation(traceData.ToString());
}
Reading DOM data
When reading DOM data using the Read(FilterElement<T>)
methods, you can opt to do a single read or retrieve the results in pages. When there is a chance that a lot of records can be returned, using paging is highly recommended. This ensures that a response is not too large, as large responses can have a negative impact on performance. It also gives you the chance to make a decision in the code to abort the action without having to retrieve all records.
Read all without paging:
var fieldDescriptorId = new FieldDescriptorID(Guid.Parse("87fd760d-13cd-41f4-85b6-405beb0f777c"));
var filter = DomInstanceExposers.FieldValues.DomInstanceField(fieldDescriptorId).Equal("MyValue");
var allInstances = helper.DomInstances.Read(filter);
Read all with paging:
var pagingHelper = helper.DomInstances.PreparePaging(filter);
var allInstances = pagingHelper.GetAll();
Read page by page:
var pagingHelper = helper.DomInstances.PreparePaging(filter); // Prepare with default page size of 500
while (pagingHelper.MoveToNextPage())
{
var currentPage = pagingHelper.GetCurrentPage();
// Handle current page of data...
}
Once you have read the DomInstance
, you can get or alter the field values. See the examples for more info on how to do this.
Tip
When reading multiple DomInstances
using their IDs, it is more efficient to build one large OR filter and read them in a single call instead of retrieving them one by one. The Tools.RetrieveBigOrFilter()
helper method is available for this. See DOM best practices for more info.
Filtering
To specify which DomInstances
need to be retrieved from the database, you can build filters using the FilterElement
structures.
Start a filter by specifying the field you want to filter on using the DomInstanceExposers
class. Once a field is selected, choose the comparer and provide a value. These filters can then be concatenated with AND and OR conditions.
Base properties:
Field | Type | Supported Comparer |
---|---|---|
Id | string | Equal, NotEqual |
SectionDefinitionIds | List<Guid> | Contains, NotContains |
SectionIds | List<Guid> | Contains, NotContains |
DomDefinitionId | Guid | Equal, NotEqual |
Name | string | Equal, NotEqual, Contains, NotContains |
StatusId | string | Equal, NotEqual, Contains, NotContains |
LastModified | DateTime | LessThan, GreaterThan |
LastModifiedBy | string | Equal, NotEqual, Contains, NotContains |
CreatedAt | DateTime | LessThan, GreaterThan |
CreatedBy | string | Equal, NotEqual, Contains, NotContains |
Fields:
These are the supported comparers when filtering on DomInstance
values using the DomInstanceExposers.FieldValues.DomInstanceField()
exposer.
Field Type | Supported Comparer |
---|---|
string | Equal, NotEqual, Contains, NotContains |
double | Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual |
long | Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual |
TimeSpan | Equal, LessThan*, GreaterThan* |
Boolean | Equal |
DateTime | Equal, NotEqual, LessThan, GreaterThan |
GenericEnum (int) | Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual |
List GenericEnum (int) | Contains |
GenericEnum (string) | Equal, NotEqual, Contains, NotContains |
List GenericEnum (string) | Contains |
Guid | Equals, NotEquals |
List Guid | Contains |
List string | Contains |
*Only supported for STaaS
Note
From DataMiner 10.4.5/10.4.0 [CU2] onwards, string
filters are handled as case-insensitive when using the OpenSearch database (which is how STaaS has handled string
reads since its introduction). Prior to DataMiner version 10.4.5/10.4.0 [CU2], string
filters are handled as case-sensitive.
Examples:
var domHelper = new DomHelper(engine.SendSLNetMessages, "vehicles_app");
// DOM instances linked to a specific DOM definition
var domDefinitionId = Guid.Parse("838fbabb-3651-43fb-84ea-568995b4d066"); // Vehicles definition
var definitionFilter = DomInstanceExposers.DomDefinitionId.Equal(domDefinitionId);
var allForDefinition = domHelper.DomInstances.Read(definitionFilter);
// DOM instances in the 'maintenance' status
var statusFilter = DomInstanceExposers.StatusId.Equal("maintenance");
var inMaintenance = domHelper.DomInstances.Read(statusFilter);
// DOM instances updated in the last 24 hours
var lastModifiedFilter = DomInstanceExposers.LastModified.GreaterThan(DateTime.UtcNow.AddHours(-1));
var recentlyModified = domHelper.DomInstances.Read(lastModifiedFilter);
// DOM instances where the value for FieldDescriptor with the given ID equals 'AZN-070'
var fieldDescriptorId = new FieldDescriptorID(Guid.Parse("aa675f01-c841-4572-83c9-b2710f41ea39")); // Car license plate
var valueFilter = DomInstanceExposers.FieldValues.DomInstanceField(fieldDescriptorId).Equal("AZN-070");
var specificCar = domHelper.DomInstances.Read(valueFilter);
// DOM instances matching all of the above using an AND filter
var andFilter = new ANDFilterElement<DomInstance>(definitionFilter, statusFilter, lastModifiedFilter, valueFilter);
var andResult = domHelper.DomInstances.Read(andFilter);
// DOM instances matching any of the above using OR filter
var orFilter = new ORFilterElement<DomInstance>(definitionFilter, statusFilter, lastModifiedFilter, valueFilter);
var orResult = domHelper.DomInstances.Read(orFilter);
// Combinations of OR and AND filters
orFilter = new ORFilterElement<DomInstance>(lastModifiedFilter, statusFilter, valueFilter);
andFilter = new ANDFilterElement<DomInstance>(definitionFilter, orFilter);
var combinedResult = domHelper.DomInstances.Read(andFilter);
Note
Although, this section explained reading DomInstances
, the same principles apply to all other DOM objects. Building filters is done using exposer classes and reading is done using the DomHelper
. For example, for SectionDefinitions
, this could be domHelper.SectionDefinitions.Read(SectionDefinitionExposers.Name.Contains("My Name"))
.
Important
On a DataMiner Agent that is using OpenSearch or Elasticsearch, there is a default limit of 1024 clauses in a query. This means that you can only concatenate a maximum of 1024 field filters using an "OR" filter. If this limit is not sufficient, you can adjust it using the "indices.query.bool.max_clause_count" option in OpenSearch or Elasticsearch.
For STaaS, there is no such hard limit, but we do recommend keeping the queries short.
Sorting
It is also possible to sort your results based on a specific field of a DOM instance (both core fields and FieldValues
). This sorting is done in the database, which should result in good performance. To apply this sorting, call the OrderBy
or OrderByDescending
methods on a filter. This will return a query object that can be passed to the read method of the helper.
Examples:
var domHelper = new DomHelper(engine.SendSLNetMessages, "vehicles_app");
// Build a filter
var filter = DomInstanceExposers.StatusId.Equal("maintenance");
// Sort ascending on name
var onNameQuery = filter.OrderBy(DomInstanceExposers.Name);
var orderedOnName = domHelper.DomInstances.Read(onNameQuery);
// Sort descending on last modified
var onModifiedQuery = filter.OrderByDescending(DomInstanceExposers.LastModified);
var orderedOnModified = domHelper.DomInstances.Read(onModifiedQuery);
// Sort on certain field (e.g. 'Vehicle mass')
var fieldDescriptorId = new FieldDescriptorID(Guid.Parse("253700a1-1293-4dfa-997b-86efb601d894")); // Vehicle mass
var field = DomInstanceExposers.FieldValues.DomInstanceField(fieldDescriptorId);
var onFieldQuery = filter.OrderBy(field);
var orderedOnField = domHelper.DomInstances.Read(onFieldQuery);
Note
Natural sorting is not supported. Enabling this option on the sorting API could result in poor performance since this will be executed in memory and requires all data to be loaded from the database.
Multiple instances
When multiple DomInstances
need to get created, updated, or deleted, we recommend calling the CreateOrUpdate or Delete methods on a DomInstance
CRUD helper component with a list of those DomInstances
. This feature is available from DataMiner 10.4.2/10.5.0 onwards.
For example, to create or update multiple DomInstances
:
// Create or update a list of DomInstances
var createResult = helper.DomInstances.CreateOrUpdate(domInstances);
CreateOrUpdate will consider the provided DomInstances
that already exist as updates. The other DomInstances
will be created. Providing a mix of both is supported.
Tip
For more information and best practices for using these calls, see Processing multiple DomInstances — examples.
Important
When designing the object model, consider if a high number of DomInstances
might need to be processed quickly or need to be provisioned. If this is the case, we recommend avoiding related actions such as launching script actions and history tracking.
The number of DomInstances
that can be passed to these methods is limited to 100. Since those related actions might outlive these CRUD calls, keep in mind that repeating these operations in succession can still impact the stability of the system.
Call result
When the operation fails for one of the DomInstances
, the result of those calls will contain the necessary information.
- When
CreateOrUpdate
is called, the result will contain a list ofDomInstances
that were successfully created or updated. The trace data is available perDomInstance
ID. - When
Delete
is called with a list ofDomInstances
, the result will contain a list ofDomInstance
IDs that were successfully deleted. The trace data is also available perDomInstance
ID.
If an issue occurs when an item gets created, updated, or deleted (e.g. validation), no exception will be thrown (even when ThrowExceptionsOnErrorData
is true). The result of the call can be used to check for which DomInstances
the call succeeded or failed. In addition, the trace data of that call is available and will contain the trace data for all processed DomInstances
.
In case the entire operation fails (e.g. when the storage layer fails while storing the data) a CrudFailedException
is thrown. If, in that case, ThrowExceptionsOnErrorData
was set to false, these calls will return null
and the TraceData
of the last call should be checked to get more details about the issue. For information on how to implement this flow, refer to the Unexpected issue example.
Maximum number of instances
Since these calls might trigger related actions (such as launching script actions), this could cause a high load on the system when a lot of instances are involved. A limit of 100 DomInstances
is set, to make sure those bulk operations are implemented with scalability in mind. When a higher number of instances need processing, these actions will need to be performed in batches.
You can also find this maximum number of instances for the CreateOrUpdate
or Delete
calls in the MaxAmountBulkOperation
property on a DomInstance
CRUD helper component.
If more items get passed, CreateOrUpdate
or Delete
calls will fail with a DomInstanceCrudMaxAmountExceededArgumentException
, and the message of the exception will state how many items were passed.
Special methods
In addition to the CRUD methods, the following special methods are also supported on a DomInstance
CRUD helper component:
DoStatusTransition: Used to transition a
DomInstance
from one status to another. See DOM status system.ExecuteAction: Used to execute an action in the context of a
DomInstance
that was defined on aDomBehaviorDefinition
. See DOM actions.
Stitching
The stitching functionality makes it easier to work with a DomInstance
. With this, there is no need to use the helper each time and retrieve the linked objects using an ID filter. When a DomInstance
is stitched, it is possible to:
- Retrieve the full
DomDefinition
object that theDomInstance
is linked to, by callingGetDomDefinition()
on the instance. - Retrieve the full
SectionDefinition
object that aSection
is linked to, by callingGetSectionDefinition()
on theSection
- Retrieve the full
FieldDescriptor
object that aFieldValue
is linked to, by callingGetFieldDescriptor()
on theFieldValue
.
Note
When an item is not stitched, and one of the above-mentioned get methods is called (e.g. GetDomDefinition), an exception will be thrown.
There are two ways to stitch DOM instances:
DomHelper.StitchDomInstances(List<DomInstance> domInstances)
: This will stitch the given list ofDomInstances
by retrieving all objects from the server using the SLNet callback on the helper.DomHelper.StitchDomInstances(List<DomInstance> domInstances, List<SectionDefinition> existingSectionDefinitions, List<DomDefinition> existingDomDefinitions)
: This will stitch the given list ofDomInstances
by trying to retrieve the other objects from the given lists. This is a more efficient option when you already have all necessary objects.
Note
If stitching is used and an object cannot be found, a null value will be assigned to the related property. The DomInstance
will still be marked as stitched. This way, when that property is retrieved, you can know it is not available.
For example: If the second of the two methods above is used, but the provided existingDomDefinitions
list is empty, the stitching logic will not be able to find the DomDefinition
object linked to the instance. When you try to retrieve the DomDefinition
using the DomInstance.GetDomDefinition()
method, "null" will be returned.
Attachments
From DataMiner 10.1.3/10.2.0 onwards, it is possible to save attachments with the DomHelper
. These are linked to a DomInstanceId
. You can use the Attachments
helper on the DomInstance
CRUD component.
var domHelper = new DomHelper(engine.SendSLNetMessages, PermissionTestModuleId);
var fileBytes = File.ReadAllBytes("C:\MyDocuments\ImportantDocument.txt");
// Adding an attachment
domHelper.DomInstances.Attachments.Add(domInstanceId, "ImportantDocument.txt", fileBytes);
// Get the names of all attachments
List<string> fileNames = domHelper.DomInstances.Attachments.GetFileNames(domInstanceId);
// Get the content of an attachment
byte[] file = domHelper.DomInstances.Attachments.Get(domInstanceId, "ImportantDocument.txt");
// Delete an attachment
domHelper.DomInstances.Attachments.Delete(domInstanceId, "ImportantDocument.txt");
Note
- The size limit of the attachments is determined by the Documents.MaxSize setting in MaintenanceSettings.xml. The default value for this is 20 MB. Trying to upload a larger file using the helper will result in a
DataMinerException
. - Deleting a
DomInstance
will delete all attachments from the file system. The attachments cannot be recovered. - To view or download
DomInstance
attachments, read permission is required, and to add or edit them, edit permission is required. - To include
DomInstance
attachments in a custom backup in Cube, select All documents located on this DMA. - The attachments are synced in the DMS.