I read collection of records using this script:

var entities = Get>("ReadDataUserTask2.ResultCompositeObjectList");

I want to loop through this list and set parameter with type contact to each object of the list.

The collection of records is a list of opportunityContact.

I tried converting each ICompositeObject to opportunityContact using this script:

foreach (var entity in entities)



    OpportunityContact contactInOpp = (OpportunityContact)entity;


but OpportunityContact is not a known object.

How do I access the types of the tables (no need to add data to DB or search just get the type in order to convert)?




Like 0



Hi Chani,


Here is a working example of two cases: set the string parameter value from the process that reads the collection and also modify contacts massively in the script task based on the received collection.


Here is the screenshot of the main process:

and the screenshot of the sub-process:

The idea of the sub-process is to read the collection of 4 records and their emails, Ids and Names if to be more specific. Then the read values are passed to the main process as a collection and go to the main process parameters (see that the "OutputParameters" parameter has the value of "[#SubProcess that will read all the needed data from Contacts 1.OutputRecordCollection#]").


The script task itself calls the ProcessContactNames method that is specified in the main process "Methods" tab:

The listing of the code is below:

public void ProcessContactNames() {
	string result = "";
	var contactsList = Get<ICompositeObjectList<ICompositeObject>>("OutputParameters");
	foreach (ICompositeObject item in contactsList) {
				item.TryGetValue<string>("FullNameParameter", out string ContactName);
				item.TryGetValue<string>("EmailParameter", out string ContactEmail);
				item.TryGetValue<Guid>("IdParameter", out Guid ContactId);
				result = result + " " + ContactName + " " + ContactEmail + ", ";
				ContactName = "Oscar Dylan from process";
					var contactSchema = UserConnection.EntitySchemaManager.GetInstanceByName("Contact");
					var entity = contactSchema.CreateEntity(UserConnection);
						entity.FetchFromDB("Id", ContactId);
						entity.SetColumnValue("Name", ContactName);
Set<string>("StringParameter", result);

Also add the following usings to your main process:


The idea here is to pass the collection of records from the "OutputParameters" main process parameter, process each record in the foreach cycle, compose the result string that then will be displayed on the autogenerated page to check if the process worked and also find each contact by its Id that was passed from the collection and set the name column value for each contact as "Oscar Dylan from process".


As a result the process worked perfectly:

and contact names were modified:

Please analyze the process and use the same approach on your side.


Best regards,


Oscar Dylan,

Thank you. 

Will try that.

Show all comments

Hi everyone,

I have created a script task to create new records from a csv.

I am trying to implement a method to search the db for a matching record and then update it (in case it exists).

The second part (the 'else' part, it's working fine) 

Does anybody know how to filter and search a DB table? What am I getting wrong?



void saveLine(string line, int rowNumber){



        string lineFormatted = line.Replace("\"", "");

        string[] lineSplitted = lineFormatted.Split(',');

        var LRNMBL = lineSplitted[0];

        var LRRIGA = lineSplitted[1];

        var LRDTBL = lineSplitted[3];

        var LRCANA = lineSplitted[6];

        // Creation of query instance with "Contact" root schema. 


        // An EntitySchemaQuery instance that accesses the UsrTestFTPCall table of the database.

        var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "UsrVedniteTestate");



        // Adding columns to the query.





        // Filter the query data. according to LRNMBL and 

        var esqFirstFilter = esq.createColumnFilterWithParameters(Terrasoft.ComparisonType.EQUAL,"UsrLRNMBL", LRNMBL);

        var esqSecondFilter = esq.createColumnFilterWithParameters(Terrasoft.ComparisonType.EQUAL,"UsrLRRIGA", LRRIGA);


        esq.filters.logicalOperation = Terrasoft.LogicalOperatorType.AND;


        esq.filters.add("esqFirstFilter", esqFirstFilter);




        // Get the result of the query.

        var entities = esq.GetEntityCollection(UserConnection);

        // If the data is received.

        if (entities.Count > 0)//Record exists in the db --> update


           var recordToUpd = entities[0];

           recordToUpd.SetColumnValue("UsrLRNMBL", LRNMBL);

           recordToUpd.SetColumnValue("UsrLRRIGA", LRRIGA);

           recordToUpd.SetColumnValue("UsrLRDTBL", LRDTBL);

           recordToUpd.SetColumnValue("UsrLRCANA", LRCANA);




            //the record doesn't exist --> Create one

               var TestObj = UserConnection.EntitySchemaManager.GetInstanceByName("UsrTestFTPCall").CreateEntity(UserConnection);

            //access the data position and assign it to its column


            //Associate new column values to old Col values

            TestObj.SetColumnValue("UsrName", rowNumber.ToString());

            TestObj.SetColumnValue("UsrLRNMBL", LRNMBL);//riferimento testata di vendita

            TestObj.SetColumnValue("UsrLRRIGA", LRRIGA);//riferimento riga all'interno della stessa vendita

            TestObj.SetColumnValue("UsrLRDTBL", LRDTBL);

            TestObj.SetColumnValue("UsrLRCANA", LRCANA);






Like 0




I don't see anywhere in the code where you're saving the updates made to the entity in recordToUpd. Try adding the following to have it save the values in the database:



Hello Federica,

Yes, try to add the method that Ryan recommended you. It will help to resolve the issue.

Best Regards,


Hi Ryan,


The problem is to access and filter records in the db.

That part of the script ain't working.

Hi Tetiana Bakai,

The main issue atm lays in the filtering and db-access part.

Show all comments

Hi everyone, 

I am setting up a Business process in order to create new records in a custom section. The data is stored in a List returned by a method. 

How can I loop through the collection and create new entities based on the values I need?

Like 2



Problem solved by moving the code block inside of a function called in the method that loops through the collection. 

Show all comments

При попытке добавления блока с пользовательским кодом возникает ошибка

An attempt to add a script task causes an error

System.InvalidCastException: Specified cast is not valid.
   at Terrasoft.Core.Process.ProcessModel.GetParameterValue[T](FoundParameterData result)
   at Terrasoft.Core.Process.Process1MethodsWrapper.ScriptTask1Execute(ProcessExecutingContext context)
   at Terrasoft.Core.Process.ProcessScriptTask.InternalExecute(ProcessExecutingContext context)
   at Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)

Сам код в блоке выглядит так: 

The code itself looks as following:

double result = Get<double>("amount") * Get<float>("rate") / Get<int>("division");
Set("result", result);
return true;

У меня нет опыта работы с BPMN, поэтому я не знаю, где именно я ошибся. Всё, что делают формулы - это запись данных из справочника в параметры процесса.

Заранее спасибо!

I'm totally new to BPMN so I have no idea where the error may be. The formulas only save lookup values into process parameters. 

Thanks in advance!

File attachments
Like 0



By the way, if there is a list of data type matches for decimal values (as I understood, float does not match all of them), I would really appreciate a link.

Кстати, если существует список соответствий типов данных для дробных значений (как я понял, float подходит не для всех), я был бы очень благодарен за ссылку.

Я нашёл необходимый тип данных, им оказался decimal. Вопрос можно закрыть

Вот ссылка на перечнь соответствующих типов:

Элемент процесса [Задание-сценарий] | Creatio Academy (terrasoft.ru)

I've found the necessary data type, it turned out to be decimal.

Above there is a link to a list of data type matches

Show all comments

Hi All,

Can some one suggest a better approach to loop through multiple records and modify them. Please note that the trigger is coming from Signal (Record Added).


Basically, I am trying to add multiple records using Multi-select lookup detail built using LookupMultiAddMixin.

Reference - https://academy.creatio.com/documents/technic-sdk/7-15/adding-multiple-records-detail?_ga=2.11560502.366292848.1628844467-134737415.1626226816 

This is configured in a custom detail and on add, business process places that many number of rows to that detail. Now based on the detail object specific column value, I want to update all the contact records that is mapped with that detail.


But what I notice is it is updating only 1 record. Kindly suggest how this could be achieved.


Like 0



Hi Anupama, 


One of the ways to create a loop in your process to work with the collection of records is  to create a sub-process and pass the collection into the subprocess. 

You can refer to the example below and create the process you need: 



Signal "Contact Added" element: 

Read Data "Read Contact" element:



For the sub-process, you would need to specify the [Parameters] of it:



And make a filter of the element within the sub-process based on the ID:

And finally, you would need to specify this parameter in the parent Business Process:



You may also find these academy Articles useful:






Hope this helps!


Thank you!





Thanks Yurii Sokil for the detailed instruction and the sequential  Execution Mode is something I haven't tried it before. Would definitely try that.


In between I tried another approach where-in at the entry point where the Signal action is placed, I unchecked the option of "Run following elements in the background". With this, until the process is completed, I was able to read the required values and add/edit/delete multiple records.



Show all comments


Let's say that I use a script task to get a request from a third party application and that request sends creatio a json with arrays.


What I need to do is to insert that data into some tables.


Can I pass the array to a collection parameter and then use it in my business process or do I need to insert the data via sql in the script task?




Like 0



Hi Raz, 


In fact, an array will work almost the same as a collection, so it doesn't make any sense to pass array into collection, but in this case you need to read this json data and then pass it through the collection for your further actions.


Please check out some practical examples of how to read and update data in script task: 











Bogdan L.



Show all comments



I have a business process where I need to read the read element values in a script task.

When the read element is set to "read a collection of records" I'm using the following code:

var AccountsData = Get>("ReadDataUserTask12.ResultCompositeObjectList");

var AccountData = AccountsData.First();

var AccountAddress="";

AccountData.TryGetValue("Address", out AccountAddress);


What change do I need to do when the read element is set to "read the first record"?






Like 0











string name = string.Empty;
string email = string.Empty;
Guid RecordId = Guid.Empty;
 * This approach should not be used in production
 * Please create process parameters and set values with standard tools (i.e. Formula)
 * ReadDataUserTask1 is the Code of "Read One Contact" element
var re = context.Process.FindFlowElementByName("ReadDataUserTask1").GetPropertyValue("ResultEntity");
if (re.TryGetPropertyValue("Email", out object _email))
	email = _email.ToString();
if (re.TryGetPropertyValue("Name", out object _name))
	name = _name.ToString();
if (re.TryGetPropertyValue("Id", out object _id))
	if(Guid.TryParse(_id.ToString(), out Guid Id))
		RecordId = Id;
//Set values to process parameters
Set&lt;string&gt;("Name", name);
Set&lt;string&gt;("Email", email);
Set&lt;Guid&gt;("RecordId", RecordId);
return true;




Kirill Krylov CPA,

Hi Kirill,


I don't understand you code.

So if shouldn't use this code in production.


what should I do?


I don't manage to get the values from ResultEntry.




Kirill Krylov CPA,

Your code is exactly what I need if I don't want to use "get a set of records" and if I don't what to use the "Formula" process element.

Why not to use it in production?

Show all comments

Dear Community,


I am trying to copy values from a field and lookups to put it in the "Name" fields before saving.

I use the following code in the script task but I don't know how to get the value from a lookup:

Entity.Name = $"{Entity.Code } - {Entity.Description}";

Code being the lookup.

So if you create a record in a lookup it would go like this:


[           ][ 001 ][Code for info]

The Name should automatically be filled with "001 - Code for info" after saving.

What is the correct way to set the script?

Thank you!



Kind regards,



Like 0





Just add on saving event in your lookup entity, and add a script


Entity.SetColumnValue("Name", string.Format("[{0}][{1}]", Entity.GetTypedColumnValue&lt;string&gt;("Code"), Entity.GetTypedColumnValue&lt;string&gt;("Descritpion"));


Dmytro Oliinyk,



Thank you but that didn't seem to work for me, this was the solution for me:


var name = Entity.GetColumnValue("Name");
var description = Entity.GetColumnValue("Description");
var esq = new EntitySchemaQuery(Entity.Schema);
var CodeEntity= esq. GetEntity(UserConnection, Entity.PrimaryColumnValue);
if (CodeEntity != null) {
	var columnUsrCodeName = CodeEntity .GetTypedColumnValue&lt;string&gt;("Code_Name");
	string fullName= $"{name}: {columnUsrCodeName } - {description}";
	Entity.SetColumnValue("Name", fullName);
return true;

Let me know if there's an easier way to do this.



Kind regards,


Show all comments

I have a business process that reads a collection of data.

Two of the fields that are being read are datetime fields.

Because the read data process reads many rows, I'm reading those rows in a script task and using the following code:


var ProductLines = Get>("ReadDataUserTask1.ResultCompositeObjectList");

    foreach(var ProductLine in ProductLines) {


It's very important to understand that inside the foreach loop I'M NOT TRYING TO GET THE DATETIME FIELDS, BUT OTHER STRING TYPE FIELDS.


Once I run the process I get the following error message:

Terrasoft.Common.UnsupportedTypeException: Type "System.TimeSpan, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089" is not supported.

   at Terrasoft.Common.CompositeObject.Add(String key, Object value)

   at Terrasoft.Common.CompositeObjectListUtilities.Transform(ICompositeObject source, IReadOnlyDictionary`2 keyMap)

   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()

   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)

   at Terrasoft.Common.CompositeObjectListUtilities.Transform[T](IEnumerable`1 source, IReadOnlyDictionary`2 keyMap)

   at Terrasoft.Core.Process.Configuration.ReadDataUserTask.FillResultCompositeObjectList(IProcessParametersMetaInfo schemaElement, EntityCollection entityCollection)

   at Terrasoft.Core.Process.Configuration.ReadDataUserTask.InternalExecute(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessActivity.ExecuteElement(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessActivity.ExecuteItem(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)


I'm looking forward to having your assistance with the issue.


Best Regards,


Like 0



Hi Raz, 


Could you please provide a full script-task code you use so we will be able to test it at our end?




Show all comments

we have a custom button on the section page that triggers a process.

When the business process returns to the section page code, is it possible to capture a return parameter from the process  ? how ?

Like 0



The issue is that the process will execute asynchronously. The only way to get the value back from the process is, instead of using it as an output param, to send it as a message using a script task in the process that you will retrieve with client-side code on the page. 

You can see an article outlining how to do this here: https://customerfx.com/article/sending-a-message-from-server-side-c-to-…


Basically, at the end of your process, you'll add a script task. In that script task you'll get the param value, then send it as a message (as outlined in the article). Then, in your page code, you'll listen for that message, check to make sure it's the message sent from your process, and then read the value and do whatever is needed with it.


Show all comments