Сделал следующие методы для валидации.

Нужно посчитать количество данных по условиям в группе фильтров. Все переменные присваивают правильные значения, кроме activeEverydayConcertCount на этапе чтения выборки. В чем проблема?

maxEverydayActive: function() {

                var invalidMessage = "";

                var activeEverydayConcertCount = 0;

                var maxActiveEverydayConcertCount = 0;

                Terrasoft.SysSettings.querySysSettingsItem("UsrMaxEverydayActiveProgram", function(value) {

                    maxActiveEverydayConcertCount = value;

                }, this);

                var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {

                    rootSchemaName: "UsrConcertProgram"

                });

                esq.addAggregationSchemaColumn("Id", Terrasoft.AggregationType.COUNT, "CountEntities",

                Terrasoft.AggregationEvalType.ALL);

                

                var filterGroup = this.Terrasoft.createFilterGroup();

                

                filterGroup.add("concertsIsActive",

                this.Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrIsActive", "1"));

                filterGroup.add("performancePeriodEveryday",

                this.Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,

                "UsrPerformancePeriod", "85A8C133-FF83-4290-9F69-B34EAF627F8C"));

                

                esq.filters.addItem(filterGroup);

                

                esq.getEntity(function(result) {

                        if (result.success){

                            activeEverydayConcertCount = result.entity.get("CountEntities"); - здесь не присваивается значение. Должно быть 4. По БД проверил

                        }

                }, this);

                

                if (activeEverydayConcertCount >= maxActiveEverydayConcertCount) {

                    invalidMessage = this.get("Resources.Strings.MaximumActiveEverydayConcerts");

                }

                

                return {

                    invalidMessage: invalidMessage

                };

            },

            setValidationConfig: function() {

                this.callParent(arguments);

                this.addColumnValidator("UsrIsActive", this.maxEverydayActive);

                this.addColumnValidator("UsrPerformancePeriod", this.maxEverydayActive);

            }

Нравится

2 комментария

Пробовал различные операции без группы фильтров, а с обычными, без условия и тд. Ничего...

 

Paul_lgb,

Добрый день. Все дело в том, что у вас даже не вызывается callback вызова getEntity (если вызывается, то это странно, возможно в вашей версии еще есть такое поведение).

Функция getEntity имеет 3 параметра:

1. primaryColumnValue

2. callback

3. scope

Функция getEntity будет возвращать вам все колонки, относящиеся к этой entity.

Пример:

getEntity("<здесь Id контакта>", function(resullt) {}) //т.е. будет фильтрация по Id контакта

Для получения количества записей, без "фильтрации" нужно использовать функцию getEntityCollection(callback), но она асинхронна, поэтому это нужно учесть.

 

Показать все комментарии

Есть такой метод:

addRecords: function(detailColumnName, segmentName, isEditableSegment) {

            var masterId = this.get("MasterRecordId");

            var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {

                rootSchemaName: this.entitySchemaName

            });

            esq.addColumn(segmentName);

            esq.filters.add("masterFilter", Terrasoft.createColumnFilterWithParameter(

                this.Terrasoft.ComparisonType.EQUAL, detailColumnName, masterId));

            esq.filters.add("isDeletedFilter", Terrasoft.createColumnFilterWithParameter(

                this.Terrasoft.ComparisonType.EQUAL, "IsDeleted", false));

            esq.getEntityCollection(function(result) {

                var existsContactsCollection = [];

                if (result.success) {

                    result.collection.each(function(item) {

                        existsContactsCollection.push(item.get(segmentName).value);

                    });

                }

                var config = {

                    entitySchemaName: segmentName,

                    multiSelect: true,

                    columns: ["Type"]

                };

                

                var isAccount;

                if (segmentName === "Account") {

                    config.filters = Ext.create("Terrasoft.FilterGroup");

                    config.filters.add("first", Terrasoft.createColumnFilterWithParameter(

                        Terrasoft.ComparisonType.EQUAL, "Type", "b32e9350-aac5-47ca-89c5-b987205a510f"));

                    isAccount = true;

                }

                if (existsContactsCollection.length > 0) {

                    var existsFilter = Terrasoft.createColumnInFilterWithParameters("Id", existsContactsCollection);

                    existsFilter.comparisonType = Terrasoft.ComparisonType.NOT_EQUAL;


                    existsFilter.Name = "existsFilter";

                    if (isAccount) {

                        config.filters.add("second", existsFilter);

                    } else {

                        config.filters = existsFilter;

                    }

                }

                this.openLookup(config, function(config) {

                    methods.addRecordsCallback.call(this, config, detailColumnName, segmentName);

                }, this);

            }, this);

        },

где detailColumnName = "Campaing",

segmentName = "Product",

entitySchemaName = "ProductUsage"

В ProductUsage есть идентификатор родительского объекта (Campaing) и идентификатор продукта (Product)

Он нужен для того, чтобы лукап выводил только те записи, которых нет в детали для этого объекта и отрабатывает корректно, но вот когда на детали больше записей, чем 2100, БД SQL выдает ошибку, что конструкция IN принимает максимум 2100 параметров, поэтому я решил переделать запрос под конструкцию NotExists.

Изменил этот метод с фильтрами на следующий:

addNotExistsRecords: function(detailColumnName, segmentName, isEditableSegment) {

            var masterId = this.get("MasterRecordId");

            var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {

                rootSchemaName: this.entitySchemaName

            });

            esq.addColumn(segmentName);

            esq.filters.add("masterFilter", Terrasoft.createColumnFilterWithParameter(

                this.Terrasoft.ComparisonType.EQUAL, detailColumnName, masterId));

            esq.filters.add("isDeletedFilter", Terrasoft.createColumnFilterWithParameter(

                this.Terrasoft.ComparisonType.EQUAL, "IsDeleted", false));

            esq.filters.add("isEqualsTo", Terrasoft.createColumnFilterWithParameter(

                this.Terrasoft.ComparisonType.EQUAL, "Product.Id", "ProductId"));

                

            var config = {

                entitySchemaName: segmentName,

                multiSelect: true,

                columns: ["Type"]

            };

            

            var isAccount;

            if (segmentName === "Account") {

                config.filters = Ext.create("Terrasoft.FilterGroup");

                config.filters.add("first", Terrasoft.createColumnFilterWithParameter(

                    Terrasoft.ComparisonType.EQUAL, "Type", "b32e9350-aac5-47ca-89c5-b987205a510f"));

                isAccount = true;

            }

            

            var existsFilter = Terrasoft.createNotExistsFilter("Id", esq);

            existsFilter.Name = "existsFilter";

            if (isAccount) {

                config.filters.add("second", existsFilter);

            } else {

                config.filters = existsFilter;

            }

            

            this.openLookup(config, function(config) {

                methods.addRecordsCallback.call(this, config, detailColumnName, segmentName);

            }, this);

        },

 

Однако при выполнении происходит ошибка errorCode: "NotSupportedException", message: "None", stackTrace: undefined, errors: Array(0)

Где я ошибся при построении фильтров?

По сути нужно повторить такой запрос:

select Id from Product where NOT EXISTS(select Id from ProductUsage where CampaignId = 'f39db115-d2f4-4936-b415-bf6543187463' AND IsDeleted = 'false' AND Product.Id = ProductId)

 

Нравится

1 комментарий
Лучший ответ

Для начала посмотрите в SQL Server профайлер, какой запрос уходит в базу данных - таким образом Вы сможете понять, в чем заключается ошибка в конкретном случае.

Также, как вариант, Вы можете реализовать получение нужных Вам записей на стороне сервера. Подробное обсуждение можете посмотреть здесь.

Для начала посмотрите в SQL Server профайлер, какой запрос уходит в базу данных - таким образом Вы сможете понять, в чем заключается ошибка в конкретном случае.

Также, как вариант, Вы можете реализовать получение нужных Вам записей на стороне сервера. Подробное обсуждение можете посмотреть здесь.

Показать все комментарии

Здравствуйте! Необходимо с помощью ESQ (не Select !) реализовать такой запрос

select Number
from Document
order by CreatedOn desc

Столкнулся с проблемой: чтоб задать сортировку по колонке, ее необходимо добавить в запрос, то есть по факту получиться такой запрос

select Number, CreatedOn
from Document
order by CreatedOn desc

В моем случае включить в выборку нужно именно одну колонку.Подскажите, как задать сортировку без добавления колонки?

Нравится

6 комментариев

Как вариант думаю можно попробовать создать представление (view) которое отсортирует как вам нужно и вернет нужное вам количество колонок

Максим а в чем разница сколько колонок в запросе? 2 или 1. Вы же не делаете группировку и при этом сортировку. Суть своей задачи более подробно поясните.

Суть в том, что это будет подзапрос в другом запросе и мне нужно возвращать именно одну колонку из подзапроса. Например

select
	p.Number as Number,
	(
		select top 1 d.Number
		from Document d
		where d.ProjectId = p.Id and
		d.TypeId = 'DC2768E3-8767-4E59-AD83-2DC7C3B40DAA'
		order by d.CreatedOn desc
	) as LastDocument
from Project p 

И таких подзапросов больше одного, поэтому обычный join не подходит

Тогда вам Максим нужно использовать не ESQ а Select конструкцию и тогда все у вас взлетит. Так как ESQ в конце Генерирует результирующий запрос, а SELECT вы сами описываете весь свой запрос. Я бы пошел по пути SELECT.

Власов Михаил Викторович,

 

спасибо за ответ. Насчет класса Select я знаю. Но вот выборка реализована уже с помощью Esq, и просто необходимо в запрос добавить несколько колонок в виде подзапросов. Не хочеться переписывать работающий код.

В таком случае можно построить одну большую View с колонкой-подзапросом, зарегистрировать как схему и работать в ESQ с ней.

Показать все комментарии

Здравствуйте! Подскажите, а как добавить в фильтры серверного EntitySchemaQuery подзапрос или где в системе можно найти пример? На SQL запрос выглядит следующим образом:

SELECT
   * 
FROM
   [Contract] 
WHERE
   StartDate = (
        SELECT MAX(c.StartDate)
        FROM Premises p
        JOIN PremisesInContract pic ON p.Id = pic.PremisesId
        JOIN Contract c ON spic.ContractId = c.Id
        WHERE p.Id = --@someparameter
   )

 

Нравится

1 комментарий

Реализовала такой запрос:

var esqKit = new EntitySchemaQuery(userConnection.EntitySchemaManager, "Kit");

                EntitySchemaQuery kitsCountSubQuery;

                esqKit.AddColumn("Id", AggregationTypeStrict.Count, out kitsCountSubQuery);

                esqKit.Filters.Add(esqKit.CreateFilterWithParameters(FilterComparisonType.Equal, "BTContactPatient",

                    patientId));

                EntityCollection kitsCollection = esqKit.GetEntityCollection(userConnection);

По факту выполнения на стороне sql-сервера формируется корректный sql-запрос и возвращает правильный результат, но я не понимаю, каким образом мне получить результат этого запроса.

Как называется эта колонка и как правильно обратиться к kitsCountSubQuery, чтобы получить результат запроса?

Нравится

3 комментария

Алла, нужно запомнить объект-результат AddColumn в переменную, а потом посмотреть её Name. Как тут:

var gridPageEntitySchemaQuery = (EntitySchemaQuery)GridPageEntitySchemaQuery;
var monthColumn = gridPageEntitySchemaQuery.AddColumn(gridPageEntitySchemaQuery.CreateMonthFunction(columnName));
var yearColumn = gridPageEntitySchemaQuery.AddColumn(gridPageEntitySchemaQuery.CreateYearFunction(columnName));
var aggregationValueColumn = gridPageEntitySchemaQuery.AddColumn(
	gridPageEntitySchemaQuery.CreateAggregationFunction(AggregationTypeStrict.Count,
	gridPageEntitySchemaQuery.RootSchema.PrimaryColumn.Name));
EntitySchemaQueryFilterCollection filters = gridPageEntitySchemaQuery.Filters;
filters.Add(gridPageEntitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.IsNotNull,columnName));
var entityCollection = gridPageEntitySchemaQuery.GetEntityCollection(Page.UserConnection);
string dateName = string.Empty;
int month = 0;
foreach (var item in entityCollection) {
	var aggregationValue = item.GetTypedColumnValue<double>(aggregationValueColumn.Name);
	month = item.GetTypedColumnValue<int>(monthColumn.Name);
	dateName =  item.GetTypedColumnValue<string>(yearColumn.Name)+ "-" +(month < 10 ? "0" + month.ToString() : month.ToString());
	series.Add(dateName, aggregationValue);
}

 

Зверев Александр,

Спасибо за подсказку - все получилось.

Если интересно, то данная колонка называется просто 'Column'.

А если вторую сделать?

Показать все комментарии

Не могу нигде найти, каким образом возможно получить top N в запросе на JavaScript.

Везде только примеры на С#.

Нравится

2 комментария

Похожая задача и похожая проблема ( https://community.terrasoft.ru/questions/zapros-ne-vozvrasaet-znacenie ). Используя запрос:

var vip = 0;
var recordId = item.get("Id");
var esqCase = Ext.create("Terrasoft.EntitySchemaQuery", {
rootSchemaName: "Case"
});
esqCase.addColumn("UsrVIPobr");
esqCase.getEntity(recordId, function(result) {
if (result.success) {
vip = result.entity.get("UsrVIPobr");
}
}, this);

Получаю корректный Id (по базе находится нужное обращение с нужным id и полем UsrVIPObr). В карточке обращения есть логическое поле UsrVIPobr (1 или 0), но почему-то переменная vip не меняется. Прошу помочь разобраться. Изображение удалено.

Нравится

6 комментариев
Лучший ответ

Быстров Сергей,

Добро пожаловать в мир async вычислений, коллбеков и промисов)

Вам надо весь код(который за скриншотом) перенести в коллбек-функцию getEntity. грубо говоря:

var vip=null;
esq.getEntity(id, function(p) {
     //тут vip будет не null
     var vip=...;
 
     if (vip) {....}
}, this);
//тут vip все ещё null, следующие строки кода отработают ДО результата функции getEntity
var a = ...;
....

 

То, что у вас скриншот обрывается на esq.getEntity - уже подозрительно :)

Вы используете переменную vip после выполнения getEntity?

Варфоломеев Данила,

Да, используется для сравнения с константой

Там же асинхронное выполнение. В getEntity добавляется функция, которая запустится где-то потом, а код пошёл выполняться дальше.

Быстров Сергей,

Добро пожаловать в мир async вычислений, коллбеков и промисов)

Вам надо весь код(который за скриншотом) перенести в коллбек-функцию getEntity. грубо говоря:

var vip=null;
esq.getEntity(id, function(p) {
     //тут vip будет не null
     var vip=...;
 
     if (vip) {....}
}, this);
//тут vip все ещё null, следующие строки кода отработают ДО результата функции getEntity
var a = ...;
....

 

А есть какие-то безболезненные способы заставить работать код в синхронном режиме?

Быстров Сергей,

нет. только упаковать всё в Terrasoft.chain (те же коллбеки, только в более удобоваримом виде)

Показать все комментарии

Добрый день.

Подскажите как организовать фильтр в клиентской esq по агрегированным данным. Например вот есть такая агрегирующая колонка

		putNestingColumn: function(esq) {
			var aggregationColumn = this.Ext.create("Terrasoft.AggregationQueryColumn", {
				aggregationType: Terrasoft.AggregationType.COUNT,
				columnPath: "[OpportunityProductInterest:NrbParent].Id"
			});
			if (!esq.columns.contains("HasNesting")) {
				esq.addColumn(aggregationColumn, "HasNesting");
			}
		},

А требуется, чтобы выводились только те записи, у которых есть подчиненные записи (в этой колонке значение > 0).

 

Есть метод createFilter, в который необходим передать объект класса Terrasoft.BaseExpression или наследника, но непонятно как в таком случае указать колонку, по которой считать?

		var leftExpression = Ext.create("Terrasoft.FunctionExpression", {
			functionType: Terrasoft.FunctionType.AGGREGATION,
			aggregationType: Terrasoft.AggregationType.COUNT,
	        aggregationEvalType: Terrasoft.AggregationEvalType.ALL
	});

 

Нравится

3 комментария

Мне кажется, в этом случае надо надо не createFilter, а createExistsFilter. Как тут.

createExistsFilter(columnPath)

Создает экземпляр Exists-фильтра для сравнения типа [Существует по заданному условию] и устанавливает в качестве проверяемого значения выражение колонки, расположенной по заданному пути.

Да я, к сожалению, привел нерелевантный пример задачи. Если мне нужно, чтобы значения было не более 0 (в этом случае Exists поможет), а более, скажем, 5.

PS В приведенной статье речь все же идет о серверной esq

В примере по ссылке (не комментариях) используется клиентская. Если же нужно сравнивать с числом, можно попробовать подставлять выражение колонки в createColumnFilterWithParameter.

createColumnFilterWithParameter(comparisonType, columnPath, paramValue)

Создает экземпляр Compare-фильтра для сравнения колонки с заданным значением.

comparisonType Terrasoft.ComparisonType Тип операции сравнения.

columnPath String Путь к проверяемой колонке относительно корневой схемы rootSchema.

paramValue Mixed Значение параметра.

Показать все комментарии

Добрый день,

У меня такой вопрос, есть представление VwExample, я добавил SQL сценарий на его изменение через ALTER VIEW, добавил пару колонок. При выборке через MSSQL Server все нормально выбирает.

Однако в коде почему то говорит 

Terrasoft.Common.ItemNotFoundException: Значение с именем "TestColumn" не найдено

 

Выбираю следующим образом 

 

var esqActivity = new EntitySchemaQuery(userConnection.EntitySchemaManager, "VwExample");
esqActivity.AddAllSchemaColumns(true);
var entities = esqActivity.GetEntityCollection(userConnection);

Значения получаю так: 

foreach (var entity in entities)
{
    var test = activity.GetTypedColumnValue<Guid>("TestColumn");
 
}

Такое ощущение что в BPM хранится предыдущее представление до его изменения, хотя в базе данных при Select * from VwExample" выводит все колонки, в том числе TestColumn. Я что то забываю?

Нравится

1 комментарий

ESQ берёт информацию о колонках не из самой таблицы или view в базе, а из объекта в конфигурации. Соответственно, нужно открыть дизайнер объекта и добавить и там все новые колонки.

Показать все комментарии

Добрый день.

При попытке сохранить новую запись в бд через esq возникает ошибка на методе Save():

"Ссылка на объект не указывает на экземпляр объекта..    в Terrasoft.Core.DB.Select.GetSqlText()"

Код:

var schema = UserConnection.EntitySchemaManager.GetInstanceByName("OrderProduct");
			var esqEntity = schema.CreateEntity(UserConnection);
			esqEntity.SetColumnValue("Id", entity.BpmId);
            ....
            esqEntity.SetColumnValue("CurrencyId", entity.CurrencyId);
            esqEntity.UseAdminRights = false;
            esqEntity.Save();

 

Нравится

1 комментарий

Сообщение «Ссылка на объект не указывает на экземпляр объекта» означает, что в C#-коде конфигурации или ядра в какое-то поле попадает Null, а с ним пытаются работать как с объектом. Например, обращаться к его полям и методам. Не видя полного кода и стека сложно сказать точно, где именно.

Показать все комментарии