Transactions and Operations - STARIONGROUP/COMET-SDK-Community-Edition GitHub Wiki
Introduction
[Annex C]] specifies the protocol that is to be used to read and write from an ECSS-E-TM-10-25 compliant data-source. The part of the protocol that deals with write operations is designed so that only properties of objects that have been updated need to be sent to the data-source. This is applicable to both value properties, and reference properties, including reference properties that represent [COMET-Data-Model Containment relationships.
The CDP4-COMET-SDK provides an API that makes it straightforward to perform writes to an Annex C data-source using the ThingTransaction, the OperationContainer and Operation classes. The ThingTransaction
works with POCO classes and the Cache; the OperationContainer
and Operation
classes work on the basis of DTO classes.
ThingTransaction
The ThingTransaction
is used to make a record of all the updates that need to be made to existing Things
, for the creation of new Things
or the deletion of existing Things
. The ThingTransaction
, in combination with the OperationContaier
and Operation
, is the COMET-SDK implementation of the Unit of Work design pattern that is geared towards compliance with Annex C.
Multiple Things
can be added, updated and deleted using a single ThingTransaction
, but it is also possible to stack multiple ThingTransactions
on top of eachother.
Stacked
ThingTransactions
are used in the COMET-IME to allow a user to open multiple dialogs to create, edit and delete objects. When a user presses theOk
button on a dialog, theThingTransaction
associated to that dialog is kept, when the user presses theCancel
button theThingTransaction
associated to that dialog is discarded.
TransactionContext and TransactionContextResolver
[Annex C]] specifies that write operations, in case of the JSON REST API by means of an HTTP POST request, are only allowed on 2 different routes: The SiteDirectory
route and the Iteration
route. This means that all data that is somehow a part of the SiteDirectory
[CDP4-COMET Data Model Containment hierarchy is written to the SiteDirectory
route. Data that is in the containment hierarchy of an EngineeringModel
(the other TopContainer
) is written to one of the Iteration
routes contained by the EngineeringModel
.
Even though the ThingTransaction
is used to perform create, update and deletes on multiple Things
, these things may not be from a combination of SiteDirectory and an Iteration CDP4-COMET Data Model Containment tree. In COMET-SDK terms this is called the TransactionContext.
The TransactionContextResolver class is used resolve the TransactionContext
of a specific Thing
, the context is used to initialize a ThingTransaction
.
The sample code on this page is constructed around updating an existing Person object.
// assume we have a Person object from the Cache
var context = TransactionContextResolver.ResolveContext(person);
var transaction = new ThingTransaction(context);
Add, Upadate and Delete Things
The ThingTransaction
class is used to register Things
that need to be added, updated or deleted. The CDP4-COMET Data Model Containment hierarchy plays an important role when adding or deleting Things
. All objects, with the exception of the SiteDirectory
and EngineeringModel
are contained by another object. The consequence of this is that when an object is added or deleted, this also means that the container object is updated. The ThingTransaction
class takes care of these aspects and exposes methods that allow an API developer to easily add, update and delete objects.
An Add and Delete operation of a
Thing
mean an Update of its container.
The following sample code demonstrates how to register the addittion of an EmailAddress
object with a Person
object in the ThingTransaction
.
// create a new EmailAddress object
var emailAddress = new EmailAddress();
emailAddress.VcardType = VcardEmailAddressKind.WORK;
emailAddress.Value = "[email protected]";
// create a clone of the Person object that we want to add the EmailAddres to
var personClone = person.Clone(false);
// register the EmailAddres and clone of the Person object with the ThingTransaction
transaction.Create(emailAddress, personClone);
Lets assume that the Person
object already contains a TelephoneNumber
, the following sample code demonstrates how to register that TelephoneNumber
for deletion.
var telephoneNumber = person.TelephoneNumber.First();
var telephoneNumberClone = telephoneNumber.Clone(false);
transaction.Delete(telephoneNumberClone, personClone);
At the same time we can also update some value properties of the Person
object. Since the Person
object is already registered with the ThingTransaction
we do not need to register it again.
personClone.Organization = "Starion";
OperationContainer and Operation
Once all the Added, Updated and Deleted POCO Things
are registered with the ThingTransaction
, the ThingTransaction
needs to be finalized. The FinalizeTransaction
function returns an OperationContainer
that contains the Operations
that need to be executed on an Annex C data-source.
As mentioned before, the Operation
class works with DTOs, not with POCOs. An Operation
contains the DTO representation of the original POCO and the updated cloned POCO, as well as the OperationKind which states what kind of operation it is: Create
, Update
, Delete
, or Copy
.
To execute the operations on an Annex C data-source, the OperationContainer
is provided to the write function of a Dal that implements IDal
. An IDal
makes use of the Operation in an OperationContainer to compute the differences between the original and updated DTO instances to construct the proper command to send to the data-source. An API developer should make use of the Session class to write to a data-source.
An Annex C data-source will always return the updated objects as a response to write operation. The advantage of using the Session class is that the Cache is updated with the returned results coming from the data-source.
var uri = new Uri("https://cdp4services-public.cdp4.org");
var credentrials = new Credentials("some-user-name", "some-password", uri);
var dal = new CdpServicesDal();
var session = new Session(dal, credentials);
await session.Open();
var operationContainer = transaction.FinalizeTransaction();
await session.Write(operationContainer);
A lower level Dal implementation is of course also possible.
var uri = new Uri("https://cdp4services-public.cdp4.org");
var credentrials = new Credentials("some-user-name", "some-password", uri);
var dal = new CdpServicesDal();
var cancelationTokenSource = new CancellationTokenSource();
await dal.Open(credentrials, cancelationTokenSource.Token);
var operationContainer = transaction.FinalizeTransaction();
var updatedDtos = await dal.Write(operationContainer);