Good day, colleagues.

 

When attempting to create a record in a related object using User-Task, I receive the error "Insufficient permissions to add record in object 'SomeObject'." Current permissions for this user in "SomeObject" are set to Read-only. However, when using the classes new EntitySchemaQuery(), new Entity(), and userConnection.EntitySchemaManager.GetInstanceByName("Entity_Name"), I set the UseAdminRights property to true.

 

I have used three different approaches:

 

1.
new SomeEntity(_userConnection)
{
   UseAdminRights = true
}

 

2.
new EntitySchemaQuery()
{
  UseAdminRights = true
}

 

3.
EntitySchema instanceByName = _uc.EntitySchemaManager.GetInstanceByName(typeof(EntityType).Name);
instanceByName.UseDenyRecordRights = true;

 

None of these have successfully created or retrieved the record. I request assistance in figuring out how to forcibly disable permission checks for any CRUD operations on the backend.

Like 0

Like

4 comments

Hi,

 

Example from the OmnichannelContactIdentifier (OmnichannelMessaging package):

 

var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "ContactIdentity") {
                UseAdminRights = false
            };
            esq.PrimaryQueryColumn.IsAlwaysSelect = true;
            esq.AddColumn("Contact");
            esq.AddColumn("Channel");

...

Please try this approach of specifying the UseAdminRights flag for the server esq.

In addition to Oleg's response, you can also use the Select, Insert, Update, etc classes, they bypass security since they are executing direct in the database. See https://academy.creatio.com/docs/8.x/dev/development-on-creatio-platform/8.1/direct-access-references

Also, you can get the SystemUserConnection to use for the ESQ.

Also worth noting for people who haven't used the Select, Insert, Update etc classes, they bypass all Creatio application logic, so things like Business Process triggers on record creation or update too. They are very useful, but need to be aware of that to avoid issues.

One more detail, if it isn't clear by now: the UseAdminRights flag doesn't mean "use the permissions of the administrator"...actually, the opposite is the case. It means "enable the usage of permissions".
I find the wording pretty misleading, but that's how it is ;)

Show all comments

Cheers to all.

I'm developing my custom UI component in Angular and I need to get some data from Creatio database inside of my component. I discovered there is EntitySchemaQuery class in Creatio's sdk, so I decided to use it, but I'm stuck when I need to retreive data with that ESQ as I didn't find method for that. In classic ESQ there was getEntityCollection method for that. Could you please suggest how do I retrieve data from the database? Either using ESQ or other class, but user's authorization matters.

Here is the code of component.

import { Component, OnInit, Input, Output, 
        ViewEncapsulation, EventEmitter, SimpleChanges  } from '@angular/core';
import { CrtViewElement, CrtInput, CrtOutput, EntitySchemaQuery,
          ComparisonType,  AggregationType, AggregationEvalType, isGuid} from '@creatio-devkit/common';
 
@Component({
  selector: 'usr-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.scss'],
  encapsulation: ViewEncapsulation.ShadowDom
})
/* Add the CrtViewElement decorator to the InputComponent component. */
@CrtViewElement({
  selector: 'usr-input',
  type: 'usr.Input'
})
export class InputComponent implements OnInit {
  constructor() {}
 
  @Input("recordId")
  @CrtInput()
  /* The input recordId. */
  public recordId!: string;
 
  /* Add decorators to the EventEmitter<string>() event. */
  @Output()
  @CrtOutput()
  /* Track input value changes. */
  public valueChange = new EventEmitter<string>();
 
  ngOnInit(): void {
  }
 
 
  ngOnChanges(changes: SimpleChanges) {
    console.log(changes);
 
    if (isGuid(changes["recordId"]?.currentValue)) {
      let esq = new EntitySchemaQuery("ClvObject");
      esq.addAggregationFunctionColumn("Id", AggregationType.Count, "AppCount", AggregationEvalType.All);
      esq.filters.addSchemaColumnFilterWithParameter(ComparisonType.Equal, "ClvProject", this.recordId, "currentFilter");
 
      let record = esq.getMetadata();
      console.log(record);
    }
  }
}

 

Like 2

Like

3 comments

The EntitySchemaQuery classes in the devkit don't do anything, at least not how it is exposed. The ESQ classes require an executor class that actually *runs* the query and provides the connection. We don't have access to this, the executor that runs the ESQ is not part of the devkit sdk. This is intentional/by design since they want us to use the new Model classes instead. This better anyways, the Model class is far easier and more intuitive IMO.

The intended way to get data now is the Model class, which is in the devkit sdk. Here's some articles on the topic: 

Model Query Using Filters: https://customerfx.com/article/querying-data-using-filter-conditions-vi…

Model Query for a Single Record Given it's Id: https://customerfx.com/article/retrieving-a-record-via-the-model-class-…

Also, the model class does inserts/updates/deletes:

Inserting a Record: https://customerfx.com/article/inserting-a-record-from-client-side-code…

Updating a Record: https://customerfx.com/article/updating-a-record-from-client-side-code-…

Deleting a Record: https://customerfx.com/article/deleting-a-record-from-client-side-code-…

Copying a Record: https://customerfx.com/article/copying-a-record-from-client-side-code-u…

You can also use the Model class to get an object's schema:

Get Object Schema: https://customerfx.com/article/getting-an-object-schema-using-the-model…

Ryan

Hi, Ryan. Thanks for quick reply.

Maybe you could suggest how do I need to prepare aggregate columns for the query using Model class? I tried it as described below

  async ngOnChanges(changes: SimpleChanges) {
    console.log(changes);
 
    if (isGuid(changes["recordId"]?.currentValue)) {
      const dataModel = await Model.create("ClvObject");
      const filters = new FilterGroup();
      filters.addSchemaColumnFilterWithParameter(ComparisonType.Equal, "ClvProject", this.recordId, "currentFilter");
      const records = await dataModel.load({
//        attributes: ["Id", "ClvName", "ClvType", "ClvProject.ClvCommissioning"],
        attributes: [{ 
          aggregationConfig: {
            aggregationFunction: AggregationFunction.Count,
          },
          type: "aggregation",
          path: "Id",
          name: "AppCount",
          caption: "AppCountCaption",
          dataValueType: DataValueType.Integer
        }],
        parameters: [{
            type: ModelParameterType.Filter,
            value: filters
        }]
      });
      console.log(records);
 
    }
  }

But instead of getting one record with one column "AppCount" containig 2, I get two records each containg "Id" and "AppCount" 

Ok< I found out the way. Looks like aggregationConfig isn't yet working well and functionConfig should be used instead. Here is working exampe.

  async ngOnChanges(changes: SimpleChanges) {
    console.log(changes);
 
    if (isGuid(changes["recordId"]?.currentValue)) {
 
      const dataModel = await Model.create("ClvObject");
      const filters = new FilterGroup();
      filters.addSchemaColumnFilterWithParameter(ComparisonType.Equal, "ClvProject", this.recordId, "currentFilter");
      const records = await dataModel.load({
//        attributes: ["Id", "ClvName", "ClvType", "ClvProject.ClvCommissioning"],
        attributes: [
          { 
            type: "function",
            path: "Id",
            name: "AppCount",
            caption: "AppCountCaption",
            dataValueType: DataValueType.Integer,
            functionConfig: {
              aggregation: AggregationFunction.Count,
              type: "aggregation",
              aggregationEval: "all",
            }
          }],
          parameters: [{
              type: ModelParameterType.Filter,
              value: filters
          }
        ]
      });
      console.log(records);
 
    }
  }

And result

Show all comments

Hello Community,

There is a bug in the system regarding the 'Contact in Folder' object, because apparently uses InsertQuery directly into the database, instead of the InsertQuery class.This object doesn't throw signals. How can we capture the event of an added record in such a scenario ?

Thank you

Sasori

Like 0

Like

10 comments

Hello,

 

Could you please provide us with an example of the InsertQuery which is not working?

Hello,

Object name is ContactInFolder. If you try to catch an event ( when contact is added to a Static Folder) through a Business Process, the business Process wont trigger.

My question is how to catch the event of adding Contacts to a Static Folder?

Sasori Oshigaki,

 

Hello,

 

And is the option with the business process with the timer that starts each 1 hour and reads records that were created in the previous 1 hour suitable here? You can read data and process it in this way. 

Hello Oleg,

Thats the solution we are providing for the moment. Thought that it was better to do something more performant, that doesnt overload the system by executing each hour.

Thank you

Hello,

Besides the option that Oleg provided, another variant is to create a trigger in the DB because normal events like OnInserted won't work with INSERT INTO.

Hello Dmytro,

Thank you for your answer. Is there anywhere in the system a similiar implementation of a trigger, so that we can take it as a reference while we develop our own ?

Thank you,

Sasori

The system rarely uses database triggers so it would be hard to provide a suitable example.

It would be better to search trigger examples in the DB documentation

Thank you for your reply Dmytro!

 

Hello Dmytro,

I created this trigger

CREATE OR ALTER Trigger [dbo].[trigger_InsertContactInFolderAfterEvent] 
ON [dbo].[ContactInFolder]
AFTER INSERT AS
BEGIN
SET NOCOUNT ON;
DELETE cf
FROM ContactInFolder AS cf
inner join Contact as co on cf.ContactId=co.Id
where co.[Name] like 'V3%'
END;

It practically deletes Contacts (whose name start with V3),that are added in the Static Folders. Does this added trigger may cause problems for the overall system ?

Thank you Sasori

Dmytro Vovchenko,

Hi Dmytro

Any Update ?

All the best Sasori

Show all comments

Hi Community,

 

What is the syntax for EntitySchemaQuery createColumnIsNotNullFilter in server side code?

 

Thanks

Like 0

Like

1 comments

Hello,

 

Here is the example.

function OwnerFilter() {
		return Terrasoft.createColumnIsNotNullFilter('[SysAdminUnit:Contact].Id');
	}

You can also find example it in BaseFiltersGenerateModule of NUI package.

 

Regards,

Dean

 

Show all comments

Hi all,

I am trying to insert a record to an entity using esq as follows in my web service.

[OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Json)]
        public string InsertCaseESQPostForSATS(DebitCardDataForSATS debitCardData)
        {
            try
            {
                var caseSchema = SystemUserConnection.EntitySchemaManager.GetInstanceByName("SBLSRM");
                var entity = caseSchema.CreateEntity(SystemUserConnection);
                entity.SetColumnValue("SBLAccountNumber", debitCardData.AccountNo);
                entity.SetColumnValue("SBLService", debitCardData.ServiceId);
                
                entity.SetDefColumnValues();
                var result = entity.Save();
                return result.ToString();
            }
            catch(Exception ex)
            {
                return ex.Message;
            }
        }

 

Column 'SBLService' is a lookup column and I am having problem while inserting a record, says, "Value 'SBLService' was not found.". I have checked and confirmed that the object has the column and is published fine. Can somebody assist me on this? How can I set value for a lookup column?

 

 

Like 0

Like

4 comments
Best reply

Roman Raj Bajracharya,

 

the value should be passed as an actual Id and also the column name shouldn't contain the . separator:

 

entity.SetColumnValue("SBLServiceId", Id here);

 

For example see this post https://community.creatio.com/questions/how-create-or-update-record-usi… where Dmytro provided an example of working with GUID columns.

 

Best regards,

Oscar

Hi,

 

Try SBLServiceId instead and also take a look in the database and check how is this column called there.

 

Best regards,

Oscar

Oscar Dylan,

Hi Oscar,

Thank you for the reply. How do I provide the value of Id of SBLService lookup? In the database, it is just 'Id' for the lookup id. I tried to access by doing SBLService.Id but it didn't help.

entity.SetColumnValue("SBLService.Id", debitCardData.ServiceId);

 

Roman Raj Bajracharya,

 

the value should be passed as an actual Id and also the column name shouldn't contain the . separator:

 

entity.SetColumnValue("SBLServiceId", Id here);

 

For example see this post https://community.creatio.com/questions/how-create-or-update-record-usi… where Dmytro provided an example of working with GUID columns.

 

Best regards,

Oscar

Oscar Dylan,

Hi Oscar,

Thank you very much. The record is now inserted. But I am having problem on the execution of a process that should occur when a record on this entity is created. This process is executing well when I create a new record from frontend(UI). Any ideas on this?

Show all comments

Hi,

I've this query and i would like to translate to ESQ, so far i managed to create this:

but i'm having this error: "uncaught exception: Collection item with name SysUserInRole not found".

I would like to know, why i'm getting this error? Is there a way to fix it? And if there is a better way to do that?

Best regards,

Pedro Pinheiro.

 

Like 0

Like

1 comments

Hi Pedro,



Seems like in your snippet you are setting brackets '[]' in wrong order. Systems tries to add column 'SysUserInRole' to the query which does not exist. I assume that you need to change it for the following:

esq.addColumn("=[SysUserInRole:SysUser].SysRole", "Role")



To make it more clear I have put together an example:

 

var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
					rootSchemaName: "SysAdminUnit"
				});
 
				esq.addColumn("Name");
				esq.addColumn("Contact.Name");
				esq.addColumn("=[SysUserInRole:SysRole].SysUser");
 
				var currentUserFilter = this.Terrasoft.createColumnFilterWithParameter(
						this.Terrasoft.ComparisonType.EQUAL,
						"=[SysUserInRole:SysRole].SysUser",
						Terrasoft.SysValue.CURRENT_USER.value);
 
				esq.filters.addItem(currentUserFilter);
 
				esq.getEntityCollection(function(response) {
					debugger;
				}, this);

This example generates following sql query:

 

exec sp_executesql N'
SELECT
	[SysAdminUnit].[Id] [Id],
	[SysAdminUnit].[Name] [Name],
	[Contact].[Name] [Contact.Name],
	[SysUserInRole].[SysUserId] [SysUserInRole.SysUserId],
	[SysUser].[Name] [SysUser.Name]
FROM
	[dbo].[SysAdminUnit] [SysAdminUnit] WITH(NOLOCK)
	LEFT OUTER JOIN [dbo].[Contact] [Contact] WITH(NOLOCK) ON ([Contact].[Id] = [SysAdminUnit].[ContactId])
	LEFT OUTER JOIN [dbo].[SysUserInRole] [SysUserInRole] WITH(NOLOCK) ON ([SysUserInRole].[SysRoleId] = [SysAdminUnit].[Id])
	LEFT OUTER JOIN [dbo].[SysAdminUnit] [SysUser] WITH(NOLOCK) ON ([SysUser].[Id] = [SysUserInRole].[SysUserId])
WHERE
	[SysUserInRole].[SysUserId] = @P1',N'@P1 uniqueidentifier',@P1='7F3B869F-34F3-4F20-AB4D-7480A5FDF647'

Hope it helps!



Regards,

Dmytro

Show all comments
Hi.

Our intention is create a console app (C#) using EntitySchemaQuery  that query an entity (like Account or Contact) and gets its rows to populate a local table. 

We are trying to connect our bpmonline using this example:

source: https://www.bpmonline.cz/bpmonlinesdken/UsingEntitySchemaQuery.html

//////////
// Creating a query instance, adding columns and a data source in the query.
Select selectQuery = new Select(UserConnection)
                    .Column("Id")
                    .Column("Name")
                    .From("Contact");
// Executing a database query and getting the resulting dataset.
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection())
{
    using (IDataReader reader = selectQuery.ExecuteReader(dbExecutor))
    {
        while (reader.Read())
        {
            // Handling the query results.
        }
    }
} 

/////////////

The problem is we do not know how to create the connection string (UserConnection) to our cloud services, https://mycompany.bpmonline.com.

 

How to create this UserConnection? Someone has an example or may guide us?

 

 

Like 0

Like

3 comments

Theoretically, it's possible to use bpm'online local .dll-s and create the connection. However, it's very hard and usually pointless. If you need to get data from bpm'online, please create a web service in bpm'online. The service should get the needed data and give it to the requested.

This is how to create a service. 

https://academy.bpmonline.com/documents/technic-sdk/7-14/creating-configuration-service

This is how to log in and call it

https://academy.bpmonline.com/documents/technic-sdk/7-14/executing-odata-queries-using-fiddler

Eugene Podkovka writes:

However, it's very hard and usually pointless.

I don't think it's useless.

I'm trying to achieve the same goal to increase our developers' productivity.

We usually use task script in the process designer to manipulate data using EntitySchemaQuery.

Each time, we have to update the process, run it and check the log or attach visual studio debugger (which is painful) to verify our code.

Imagine if we are able to get a UserConnection instance directly into a standalone app. we can test our functions faster and increase the overall productivity.

 @Eugene Podkovka: can you please help us!

Thank you

Mohamed

Show all comments

Hi,

       I use EntitySchemaQuery to get Entity, but I can't get primary key value of result entity. The exception said: not found "Id" (something likes this)

EntitySchemaQuery esqDetails = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "UsrExportDetails");

            esqDetails.AddColumn("Id");

            esqDetails.AddColumn("UsrCodeLevel1");

            esqDetails.Filters.Add(esqDetails.CreateFilterWithParameters(FilterComparisonType.Equal, "UsrExport", id));

            var exportDetails = esqDetails.GetEntityCollection(UserConnection);

            

            foreach    (var details in exportDetails)

            {

                var refId = details.GetTypedColumnValue("Id");

                var qrCodeRefId = details.GetTypedColumnValue("UsrCodeLevel1Id");

                

                this.Push(refId, qrCodeRefId, name, address, tel, fax);

            }

Like 0

Like

2 comments

Hi Toan Mai,

Try to name your Id column:

var idColumnName = esq.AddColumn("Id").Name;

then you can get in your foreach loop:

entity.GetTypedColumnValue<Guid>(idColumnName);

At least it worked for me.

Got the same thing yesterday : 

Replace :

esqDetails.AddColumn("Id");

 by 

esqDetails.PrimaryQueryColumn.IsAlwaysSelect = true;

And you can use the following to get the Id column : 

var recordId = details.PrimaryColumnValue;

 

Show all comments

How can I pass a callback function to GetEntityCollection function of ESQ? 

Like 0

Like

1 comments

Please debug the function in the developers console in google chrome. Once you find how it works, you'll be able to find how to pass the parameter. Additionally, you can search for the examples with the global search trough all sources in the google developers console.

Show all comments

Can I know how I can create insert queries and execute those using esq on the detail? 

Like 1

Like

7 comments

You can use the InsertQuery client-side. Here is a sample: 

var insert = Ext.create("Terrasoft.InsertQuery", {
	rootSchemaName: "UsrMyEntity"
});
 
insert.setParameterValue("UsrMyParentId", this.get("Id"), Terrasoft.DataValueType.GUID);
insert.setParameterValue("UsrMyDateProperty", new Date(), Terrasoft.DataValueType.DATE);
 
insert.execute(function() {
	// do any refreshing if needed here
}, this);

Ryan

Ryan Farley,

Great! this helps. Is there a way I can do bulk insertion of multiple records at 1 single time? Any documentation reference would be really helpful. 

Thank you

 

kumar,

To do any sort of insertions of multiple records, I would create a configuration service and call that instead from the client. It would be far more efficient that way.

Ryan

Ryan Farley,

Hi guys, that is helping me in another implementation. Is it also possible to use it as updateQuery?

Thanks.

Danilo Lage,

Yes, an UpateQuery is similar, see the following sample:

var update = Ext.create("Terrasoft.UpdateQuery", {
	rootSchemaName: "Contact"
});
 
update.filters.add("IdFilter", update.createColumnFilterWithParameter(
	Terrasoft.ComparisonType.EQUAL, "Contact", this.get("UsrContactId")));
 
update.setParameterValue("UsrSomeField", "value", Terrasoft.DataValueType.TEXT);
update.setParameterValue("UsrSomeId", someId, Terrasoft.DataValueType.GUID);
 
update.execute(function() {
	// do any needed refreshing here etc
}, this);

Ryan

Danilo Lage,

kumar,

Please see the following articles, there you can find instructions on building update, insert, delete and batch queries. 

https://academy.bpmonline.com/documents/technic-sdk/7-13/dataservice-ad…

https://academy.bpmonline.com/documents/technic-sdk/7-13/dataservice-up…

https://academy.bpmonline.com/documents/technic-sdk/7-13/dataservice-ba…

https://academy.bpmonline.com/documents/technic-sdk/7-13/creating-detai…

The examples are done using C# language in case you decide to create a web service. Also there is a JavaScript example. They are particularly the same in the syntax. There also you can find examples of cases using insert, update, delete and batch queries.

Hope you will find it helpful.

Regards,

Anastasia

Ryan Farley,

Thanks, Ryan!

 

Anastasia Botezat,

Great, Anastasia...

Show all comments