Вопрос

Доброго времени суток!Возникла необходимость учитывать регистр строки в фильтре при запросе esq С# . Никто не встречался с такой проблемой?Как это можно реализовать?

У меня такой же вопрос

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

Система полагается на стандартные настройки базы данных. В MS SQL по умолчанию регистр не учитывается, настройка меняется на уровне всей базы, как описано тут. Только учтите, что работу системы с изменёнными настройками регистрозависимости никто не тестировал и сайт может заработать некорректно в других местах.

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

Благодарю за ответ

Может кому пригодится. Решили эту проблему следующим образом - конвертировали строку в base64.

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Добрый день, подскажите, как можно написать подобный запрос на esq? Желательно на стороне сервера. Смотрел в сторону addAggregationSchemaColumn, но там можно либо посчитать количество, либо применить min, max и т.п, а эти функции работают только с числовыми полями.

select
(select top 1 Number from ContactCommunication where ContactId = c.Id and CommunicationTypeId = 'EE1C85C3-CFCB-DF11-9B2A-001D60E938C6')
from Contact c

У меня такой же вопрос

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

 Запрос в скобках:

var esq = new EntitySchemaQuery(userConn.EntitySchemaManager, "ContactCommunication");
esq.AddColumn("Number");
esq.RowCount = 1;
esq.Filters.Add(esq.CreateFilterWithParameters(
	FilterComparisonType.Equal,
	"ContactId ", contactId));
esq.Filters.Add(esq.CreateFilterWithParameters(
	FilterComparisonType.Equal,
	"CommunicationTypeId", "EE1C85C3-CFCB-DF11-9B2A-001D60E938C6"));
var collection = esq.GetEntityCollection(userConn);

 

 Запрос в скобках:

var esq = new EntitySchemaQuery(userConn.EntitySchemaManager, "ContactCommunication");
esq.AddColumn("Number");
esq.RowCount = 1;
esq.Filters.Add(esq.CreateFilterWithParameters(
	FilterComparisonType.Equal,
	"ContactId ", contactId));
esq.Filters.Add(esq.CreateFilterWithParameters(
	FilterComparisonType.Equal,
	"CommunicationTypeId", "EE1C85C3-CFCB-DF11-9B2A-001D60E938C6"));
var collection = esq.GetEntityCollection(userConn);

 

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

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

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

В Вашем случае нужно будет действовать наоборот, выбирать из таблицы Contact с добавлением колонок из таблицы детали средств связи, таких как [ContactCommunication:Contact:Id].CommunicationType и [ContactCommunication:Contact:Id].Number, по таким же колонкам можно и накладывать фильтр.

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Для отладки необходимо получить SQL текст ESQ запроса на front-end

У меня такой же вопрос

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

Насколько мне известно, такой возможности нет.

В случае с фронтендом можно смотреть запрос через SQL профайлер.

Насколько мне известно, такой возможности нет.

В случае с фронтендом можно смотреть запрос через SQL профайлер.

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Добрый день!

Пробую реализовывать запрос к данных через ESQ таким образом:

var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
                    rootSchemaName: "UsrTbl1"
                });
                esq.addColumn("Id");
                esq.addColumn("UsrPar1");esq.addColumn("UsrInfoId");
                esq.addColumn("UsrValueList.Name");//вот с такими строками уже начинается проблема

esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrValueList.Name", "значение1"));//и с такими фильтрами

 

Если нужно получить значение колонок с таблицы - rootSchemaName, то не вопрос.

Проблемы начинаются, когда пытаюсь использовать прямые ссылки или в одной запросе получать GUID, а во втором его использовать.

GUID  видимо со String плохо понимают друг друга. Если ли примеры их нормального совместного использования в рамках ESQ?

Можно ли как-то понять причины неработоспособности прямых ссылок? Или хотя бы понять как с GUID быть? Даже если я значение GUID пытаюсь вставлять так, то не работает:

esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrInfoId", "337ED96B-B658-48B0-BBB6-7FACF918C735"));

У меня такой же вопрос

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

Eсли нужно получить справочную колонку, то её название нужно указывать без приставки "Id", как в схеме таблицы:

esq.addColumn("UsrInfo")

Аналогично и с фильтрами:

esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrInfo", "337ED96B-B658-48B0-BBB6-7FACF918C735"));

Но обратите внимание, что, если у Вас фильтр построен по обратным связям, то можно писать 2 способами.

1. Через Id и тогда в качестве значения фильтра указываем Id:

var shipment = this.get("BTShipment");

sampleESQ.filters.addItem(sampleESQ.createColumnFilterWithParameter(
                    this.Terrasoft.ComparisonType.EQUAL, "[BTSampInShipment:BTSampleID].BTShipment.Id", shipment.value));

2. Через справочное поле и тогда в качестве значения указывать значение справочного поля:

var shipment = this.get("BTShipment");

sampleESQ.filters.addItem(sampleESQ.createColumnFilterWithParameter(
                    this.Terrasoft.ComparisonType.EQUAL, "[BTSampInShipment:BTSampleID].BTShipment", shipment));

А вообще, чтобы понять причину ошибки нужно отладиться на стороне клиента, если запрос уходит в базу данных, то посмотреть в SQL profiler, какой запрос идет в базу и какой результат работы этого запроса.

 

В js все Guid преобразуйте к нижнему регистру

те в вашем случае напишите что то типа esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrInfoId", "337ed.....

Eсли нужно получить справочную колонку, то её название нужно указывать без приставки "Id", как в схеме таблицы:

esq.addColumn("UsrInfo")

Аналогично и с фильтрами:

esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrInfo", "337ED96B-B658-48B0-BBB6-7FACF918C735"));

Но обратите внимание, что, если у Вас фильтр построен по обратным связям, то можно писать 2 способами.

1. Через Id и тогда в качестве значения фильтра указываем Id:

var shipment = this.get("BTShipment");

sampleESQ.filters.addItem(sampleESQ.createColumnFilterWithParameter(
                    this.Terrasoft.ComparisonType.EQUAL, "[BTSampInShipment:BTSampleID].BTShipment.Id", shipment.value));

2. Через справочное поле и тогда в качестве значения указывать значение справочного поля:

var shipment = this.get("BTShipment");

sampleESQ.filters.addItem(sampleESQ.createColumnFilterWithParameter(
                    this.Terrasoft.ComparisonType.EQUAL, "[BTSampInShipment:BTSampleID].BTShipment", shipment));

А вообще, чтобы понять причину ошибки нужно отладиться на стороне клиента, если запрос уходит в базу данных, то посмотреть в SQL profiler, какой запрос идет в базу и какой результат работы этого запроса.

 

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Пытаюсь не давать людям закрывать задачи по определенным условиям. Всё хорошо до момента, пока не надо сделать это из esq.

Точнее, функция this.callParent(arguments) никак не работает из

esq.getEntity(Id, function(result) {
    this.callParent(arguments);
}, this);

Уже пробовал сделать var self = this и вызывать от self, пробовал сохранить arguments до esq. Ничего не помогает, задача не сохраняется. 

esq надо делать обязательно, т.к. изменение в другом объекте, которое я проверяю, может сделать другой человек и мне нужно проверить это прямо перед сохранением.

Есть способ?

У меня такой же вопрос

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

Добрый день, нужно либо смотреть в сторону asyncValidate (пример есть в DocumentPageV2), либо переопределить Save.

save: function(config,flag) {
    if (flag) {
        this.callParent(arguments);
    } else {
        //Validation Block
        Terrasoft.chain(
            this.checkPhonesCount,
            function (callback, scope) {
                this.save(config||{}, true),
                    callback.call(scope || this);
            },
            this
        );
    }
 
},
/**
 * Проверка количества телефонов
 * */
checkPhonesCount: function (callback, scope) {
    var leadId = this.get("Id");
    var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
        rootSchemaName: "UsrLeadPhone"
    });
    esq.addAggregationSchemaColumn("Id", Terrasoft.AggregationType.COUNT, "Count");
 
    esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
        Terrasoft.ComparisonType.EQUAL, "UsrLead", leadId));
    esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
        Terrasoft.ComparisonType.NOT_EQUAL, "UsrPhone", ""));
    esq.filters.addItem(Terrasoft.createColumnIsNotNullFilter("UsrPhone"));
    esq.getEntityCollection(function (response) {
        if (response && response.success) {
            var collection = response.collection;
            if (collection && collection.getCount() > 0) {
                var count = collection.getByIndex(0).get("Count");
                if (count >= 1) {
                    callback.call(scope || this);
                    return;
                }
            }
            var msg = this.get("Resources.Strings.PhonesErrorMessage");
            msg = this.Ext.String.format(msg, 1);
            Terrasoft.showInformation(msg);
        }
    }, this);
},

 

Я делаю так: 

1) у кнопки сохранить bind меняю на другую функцию (пр. onBeforeSave)

2) в onBeforeSave реализую логику, а дальше вызываю/не вызываю save-метод

Также можно в save зашить проверку какого-либо параметра. Сохранять arguments, проверять параметр, если false-> вызывать свою функцию, в конце своей функции параметр = true и вызвать save с  сохр. аргументами. Тоже в принципе вариант

Добрый день, нужно либо смотреть в сторону asyncValidate (пример есть в DocumentPageV2), либо переопределить Save.

save: function(config,flag) {
    if (flag) {
        this.callParent(arguments);
    } else {
        //Validation Block
        Terrasoft.chain(
            this.checkPhonesCount,
            function (callback, scope) {
                this.save(config||{}, true),
                    callback.call(scope || this);
            },
            this
        );
    }
 
},
/**
 * Проверка количества телефонов
 * */
checkPhonesCount: function (callback, scope) {
    var leadId = this.get("Id");
    var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
        rootSchemaName: "UsrLeadPhone"
    });
    esq.addAggregationSchemaColumn("Id", Terrasoft.AggregationType.COUNT, "Count");
 
    esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
        Terrasoft.ComparisonType.EQUAL, "UsrLead", leadId));
    esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
        Terrasoft.ComparisonType.NOT_EQUAL, "UsrPhone", ""));
    esq.filters.addItem(Terrasoft.createColumnIsNotNullFilter("UsrPhone"));
    esq.getEntityCollection(function (response) {
        if (response && response.success) {
            var collection = response.collection;
            if (collection && collection.getCount() > 0) {
                var count = collection.getByIndex(0).get("Count");
                if (count >= 1) {
                    callback.call(scope || this);
                    return;
                }
            }
            var msg = this.get("Resources.Strings.PhonesErrorMessage");
            msg = this.Ext.String.format(msg, 1);
            Terrasoft.showInformation(msg);
        }
    }, this);
},

 

Еще можно создать валидатор, который будет делать все проверки и срабатывать перед сохранением записи, его например привязать к полю "состояние"

Вообще, лучше не делать такие проверки только лишь в клиентской логике. Чисто теоретически, пользователь сможет отловить выполнение функции и в отладчике перешагнуть проверку. Хорошо бы и на объекте в обработчике Saving проверять соблюдение условия.

1. Если не вчитываться в смысл задачи, а только подсказать как сделать желаемое то вот этот способ:

save: function() {
   ...
   var args = arguments;
   var parentMethod = this.getParentMethod();
   ....
   esq.GetEntity(function() {
       parentMethod.apply(this, args)
   }, this);
}

2. По смыслу же задачи, вам нужно делать валидацию, а не переопределять методы сохранения. посмотрите примеры в коде с использованием методов addColumnValidator, validate, asyncValidate. 

addColumnValidator, validate делают синхронные проверки. asyncValidate асинхронная валидация, используется когда нужно сделать например запрос в БД для проверки.

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Здравствуйте. Интересует способ использования "Group By"  в entitySchemaQuery (сервер). При поиске наткнулся на топик - https://community.terrasoft.ru/questions/gruppirovka-v-entityschemaquery , но увы, ссылка с ответом битая. 

У меня такой же вопрос

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

Пример использования на C#, документацию нашел только для клиентских запросов, но по аналогии все понятно

var query = new EntitySchemaQuery(_userConnection.EntitySchemaManager, schemaName);
var columnCount = query.AddColumn(query.CreateAggregationFunction(AggregationTypeStrict.Count, query.PrimaryQueryColumn.Name));
var countEntity = query.GetEntityCollection(UserConnection)[0];
var count = countEntity.GetTypedColumnValue<int>(comnCount.Name);
return count;

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

var esq = new Order(UserConnection);
esq.AddColumn(esq.CreateAggregationFunction(AggregationTypeStrict.Count, "Customer.Name").All());
	esq.AddColumn("Description");
	esq.AddColumn("Name");
	esq.AddColumn("Customer");

Добавит в запрос 
GROUP BY Order.Description, Document.Name, Order.CustomerId, Customer.Name;

 

 

 

 

 

Пример использования на C#, документацию нашел только для клиентских запросов, но по аналогии все понятно

var query = new EntitySchemaQuery(_userConnection.EntitySchemaManager, schemaName);
var columnCount = query.AddColumn(query.CreateAggregationFunction(AggregationTypeStrict.Count, query.PrimaryQueryColumn.Name));
var countEntity = query.GetEntityCollection(UserConnection)[0];
var count = countEntity.GetTypedColumnValue<int>(comnCount.Name);
return count;

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

var esq = new Order(UserConnection);
esq.AddColumn(esq.CreateAggregationFunction(AggregationTypeStrict.Count, "Customer.Name").All());
	esq.AddColumn("Description");
	esq.AddColumn("Name");
	esq.AddColumn("Customer");

Добавит в запрос 
GROUP BY Order.Description, Document.Name, Order.CustomerId, Customer.Name;

 

 

 

 

 

Григорий Чех,

Спасибо большое!

Вот, на всякий случай, и пример серверного кода:

EntitySchema entitySchema = UserConnection.EntitySchemaManager.GetInstanceByName("SysProcessElement");
var query = new EntitySchemaQuery(entitySchema);
EntitySchemaQueryColumn elementUIdColumn = query.AddColumn("SchemaElementUId");
EntitySchemaQueryColumn executeCountColumn = query.AddColumn(query.CreateAggregationFunction(AggregationTypeStrict.Count,
	entitySchema.PrimaryColumn.Name));
 
EntityCollection entities = query.GetEntityCollection(UserConnection);

 

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

Я для серверного кода пример и приводил :) От клиентского только документация :)

Вот документация по серверной. Ещё в этом документе есть информация.

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Добрый день,подскажите пожалуйста,а в мобильном приложении есть функция автозаполнения поля ? Если да,то как это можно организовать ? Чтобы при создании новой записи в разделе,поле автоматически заполнялось значением,что то вроде счетчика записей. Например у меня в разделе есть 10 записей - запись 1,запись 2,запись 3 ... 10. При создании новой чтобы поле Название сразу заполнялось как запись 11. Подскажите примерный ход действий(на данный момент беру запросом с базы,сортируя и беру следующее число,но такой подход не очень хороший). Может быть есть более правильный вариант ? Спасибо!

У меня такой же вопрос

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

Автонумерацию таким образом делать не нужно. Во-первых, для этого есть стандартный механизм в системе. Во-вторых, в мобильном приложении это может вызвать проблемы с совпадением номеров при синхронизации записей. Автонумерацию нужно на стороне BPM делать.

Что касается автоматической установки значений, то есть несколько вариантов. Можно сделать, например, на уровне событий объекта мобильного приложения:

Terrasoft.sdk.Model.setModelEventHandler("ActivitySKU", 
    Terrasoft.ModelEvents[Terrasoft.ModelEventKinds.Before].update,
    function(config) {
        var record = config.scope.eventConfig.records[0];
        record.set("UsrIsChecked", true);
        Ext.callback(config.success, config.scope);
});

Или с помощью Custom бизнес правила:

Terrasoft.sdk.Model.addBusinessRule("ModelName", {
    name: "RuleName",
    ruleType: Terrasoft.RuleTypes.Custom,
    events: [Terrasoft.BusinessRuleEvents.Load, Terrasoft.BusinessRuleEvents.ValueChanged],
    executeFn: function(record, rule, column, customData, callbackConfig) {
        record.set("UsrColumn", "some value");
        Ext.callback(callbackConfig.success, callbackConfig.scope);
    }
})

Третий вариант - в кастомной странице повесить на загруженную запись дополнительный обработчик на изменение записи:

onLoadRecord: function(loadedRecord) {
    this.callParent(arguments);
    loadedRecord.on("columnchanged", this.onRecordColumnChanged, this);
},

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

var control = Ext.getCmp("control_id");
control.setValue("some value");

 

Такое есть смысл на стороне сервера. Есть специальное действие в БП для получения номера по порядку.

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

Автонумерацию таким образом делать не нужно. Во-первых, для этого есть стандартный механизм в системе. Во-вторых, в мобильном приложении это может вызвать проблемы с совпадением номеров при синхронизации записей. Автонумерацию нужно на стороне BPM делать.

Что касается автоматической установки значений, то есть несколько вариантов. Можно сделать, например, на уровне событий объекта мобильного приложения:

Terrasoft.sdk.Model.setModelEventHandler("ActivitySKU", 
    Terrasoft.ModelEvents[Terrasoft.ModelEventKinds.Before].update,
    function(config) {
        var record = config.scope.eventConfig.records[0];
        record.set("UsrIsChecked", true);
        Ext.callback(config.success, config.scope);
});

Или с помощью Custom бизнес правила:

Terrasoft.sdk.Model.addBusinessRule("ModelName", {
    name: "RuleName",
    ruleType: Terrasoft.RuleTypes.Custom,
    events: [Terrasoft.BusinessRuleEvents.Load, Terrasoft.BusinessRuleEvents.ValueChanged],
    executeFn: function(record, rule, column, customData, callbackConfig) {
        record.set("UsrColumn", "some value");
        Ext.callback(callbackConfig.success, callbackConfig.scope);
    }
})

Третий вариант - в кастомной странице повесить на загруженную запись дополнительный обработчик на изменение записи:

onLoadRecord: function(loadedRecord) {
    this.callParent(arguments);
    loadedRecord.on("columnchanged", this.onRecordColumnChanged, this);
},

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

var control = Ext.getCmp("control_id");
control.setValue("some value");

 

Спасибо!

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Добрый час суток!

Немного не могу понять как построить запрос на UPDATE в мобильном приложении.

Например я хочу сделать такой запрос SQL

UPDATE TEST SET IsChecked = 1 WHERE Question = '' and Answer = ''

Я делаю так:
        var filters = Ext.create("Terrasoft.Filter", {
                type: Terrasoft.FilterTypes.Group,
                logicalOperation: Terrasoft.FilterLogicalOperations.And
            });
        filters.addFilter(Ext.create("Terrasoft.Filter", {
                property: "Question ",
                value: multiAnswerId // тут Id Question (для фильтра как выше)
        }));
        filters.addFilter(Ext.create("Terrasoft.Filter", {
                property: "Answer ",
                value: answerVariantId // тут Id Answer(для фильтра как выше)
        }));
        var sql = Terrasoft.Sql.UpdateBuilder.build({
                model: "Test", //Таблица в которую хочу сделать запрос
                queryConfig: queryConfig, //что это ?
                record: record, // что это?
                filter: filters,// это у меня есть
                includeOnlyModifiedColumns: true // что это?
        });
        sqls.push(sql);
        

Подскажите пожалуйста,как мне в мой обьект который я бросаю (var sql = ...) добавить по сути SET IsChecked =1 ? Ведь фильтры я уже сделал,а как сформировать немного не пойму.. может мне даже QueryConfig и includeOnlyModifiedColumns вообще ну нужны ? и достаточно как то константами сделать ? Спасибо заранее!

У меня такой же вопрос

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

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

Вот пример фильтрации и перебора:

// Создание экземпляра хранилища для данных модели Contact.
var store = Ext.create('Terrasoft.store.BaseStore', {
    model: 'Contact'
});
 
// Создание конфигурационного объекта с дополнительными параметрами запроса на выборку данных.
var queryConfig = Ext.create('Terrasoft.QueryConfig', {
    // Определение колонок, которые будут возвращены в запросе.
    columns: ['Name', 'Id', 'Account'],
    // Имя модели, к которой выполняется запрос.
    modelName: 'Contact'
});
 
// Загрузка данных в хранилище. Будет возвращена первая страница данных.
store.loadPage(1, {
    queryConfig: queryConfig,
    // Дополнительно указывается фильтрация возвращаемых данных по колонке Name.
    filters: Ext.create('Terrasoft.Filter', {
        // Имя колонки, по которой выполняется фильтрация.
        property: 'Name',
        // Значение для фильтрации.
        value: 'Test Name'
    }),
    // Функция обработки результатов выполнения запроса.
    callback: function(records, operation, success) {
        // Получение первой записи возвращенного набора.
        var loadedRecord = records[0];
        if (loadedRecord) {
            // Получение значения поля Account.
            var contactAccount = loadedRecord.get('Account');                                                                                                    
            if (contactAccount) {                                                                                                                   
                // Выполнение действий с полученным значением.
            }
        }
    },
    scope: this
});

Вот пример изменения и сохранения записи (но новой, а не существующей):

var record = Ext.create('Contact');
record.phantom = true;
//свойство модели phantom указывает на то, новая ли это запись или существующая
record.set('Name', 'New Contact');
 
record.save({
    success: function() {
        ...
    },
    failure: function(exception) {
        Terrasoft.MessageBox.showException(exception);
    },
    queryConfig: Ext.create('Terrasoft.QueryConfig', {
        modelName: record.self.modelName,
        columns: ['Name']
    }
}, this);

 

А,разобрался,засейвить забыл. Спасибо,но результат тот же что и при обычном выполнении синхронизация с освновной базой  не работает. Вот полный код:

var store = Ext.create('Terrasoft.store.BaseStore', {
            model: 'SuInterviewAnswerChoice'
        });

        var queryConfig = Ext.create('Terrasoft.QueryConfig', {
            columns: ['SuInterviewQuestion', 'SuAnswer', 'SuIsChecked'],
            modelName: 'SuInterviewAnswerChoice'
        });
        
        store.loadPage(1, {
            queryConfig: queryConfig,
            filters: Ext.create('Terrasoft.Filter', {
                property: 'SuInterviewQuestion',
                value: multiAnswerId
            }),
            callback: function(records, operation, success) {
                for(var i =0; i<records.length;i++){
                    if(records[i].data.SuAnswer === answerVariantId){
                        var isChecked = records[i].get('SuIsChecked');
                        if(!isChecked){
                            records[i].set('SuIsChecked',true);
                            records[i].save({
                                success: function() {
                                    console.log('Successfully');
                                },
                                failure: function(exception) {
                                    Terrasoft.MessageBox.showException(exception);
                                },
                                queryConfig: Ext.create('Terrasoft.QueryConfig', {
                                    modelName: records[i].self.modelName,
                                    columns: ['SuIsChecked']
                                })
                            }, this);
                            return;
                        }
                    }
                    
                }
            },
            scope: this
        });

 

 

Вероятно, при синхронизации система не видит, что запись менялась. Проверьте, меняет ли эта логика поле с датой изменения. И что будет, если его менять.

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

да,меняет. Поле ModifiedOn меняется. Подскажите пожалуйста еще,как правильно написать Insert,спасибо!

Зверев Александр, Просто документации по мобилке в плане этого очень мало.обрываю исходники пишу по примерам +- но синхронизация так и не появляется.

Зверев Александр пишет:

Вот пример изменения и сохранения записи (но новой, а не существующей):


 
var record = Ext.create('Contact');
record.phantom = true;
//свойство модели phantom указывает на то, новая ли это запись или существующая
record.set('Name', 'New Contact');
 
record.save({
    success: function() {
        ...
    },
    failure: function(exception) {
        Terrasoft.MessageBox.showException(exception);
    },
    queryConfig: Ext.create('Terrasoft.QueryConfig', {
        modelName: record.self.modelName,
        columns: ['Name']
    }
}, this);

или я так понимаю вот это можно использовать вместо InsertBuilder?

 

Да, лучше вместо InsertBuilder использовать редактирование и сохранение записи.

Зверев Александр,Спасибо

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

Извиняюсь,подскажите пожалуйста,какая есть возможность в мобильном приложении сделать код синхронным ?  Дело в том,что мне нужно дождаться получения данных из базы,а уже потом с ними делать манипуляции,а код соответственно идет дальше и в колбек заходит уже тогда,когда нужная мне область кода прошла. Спасибо!

Зверев Александр пишет:

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

Вот пример фильтрации и перебора:


 
// Создание экземпляра хранилища для данных модели Contact.
var store = Ext.create('Terrasoft.store.BaseStore', {
    model: 'Contact'
});
 
// Создание конфигурационного объекта с дополнительными параметрами запроса на выборку данных.
var queryConfig = Ext.create('Terrasoft.QueryConfig', {
    // Определение колонок, которые будут возвращены в запросе.
    columns: ['Name', 'Id', 'Account'],
    // Имя модели, к которой выполняется запрос.
    modelName: 'Contact'
});
 
// Загрузка данных в хранилище. Будет возвращена первая страница данных.
store.loadPage(1, {
    queryConfig: queryConfig,
    // Дополнительно указывается фильтрация возвращаемых данных по колонке Name.
    filters: Ext.create('Terrasoft.Filter', {
        // Имя колонки, по которой выполняется фильтрация.
        property: 'Name',
        // Значение для фильтрации.
        value: 'Test Name'
    }),
    // Функция обработки результатов выполнения запроса.
    callback: function(records, operation, success) {
        // Получение первой записи возвращенного набора.
        var loadedRecord = records[0];
        if (loadedRecord) {
            // Получение значения поля Account.
            var contactAccount = loadedRecord.get('Account');                                                                                                    
            if (contactAccount) {                                                                                                                   
                // Выполнение действий с полученным значением.
            }
        }
    },
    scope: this
});

 

Работайте асинхронно, через callback.

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

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

Основная логика bpm'online реализуется в веб-версии, мобильная имеет вспомогательное применение, её SDK не настолько подробен и не включает всех возможных сценариев. Если у Вас есть необходимость в какой-то логике, которую не реализовать иначе, можете завести идею, описать там подробно своё пожелание и, возможно, в новых версиях такое реализуют.

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Всем привет.

Ввиду не внятности документации прошу помощи.

Как составить такой запрос используя ESQ на клиенте?

SELECT account.UsrINN,(SELECT TOP(1) ModifiedOn FROM Activity activity WHERE activity.AccountId=account.Id ORDER BY ModifiedOn) AS LastComunicationDate  FROM Account account  WHERE account.UsrINN = '7730616959' 

Собственно запрос выводит дату последней измененной активности по контрагенту.

 

 

У меня такой же вопрос

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

Последовский Роман,

А так?

var esq = Ext.create("Terrasoft.EntitySchemaQuery", { rootSchemaName: "Account" });
esq.addColumn("UsrINN");
esq.addAggregationSchemaColumn("[Activity:Account].ModifiedOn", 5, "MaxModifiedOn");
esq.filters.addItem(esq.createColumnFilterWithParameter(3, "UsrINN", "7730616959"));
esq.getEntityCollection(function (result) {
	if (result.success && result.collection.getCount() > 0) {
		result.collection.collection.each(function(item) {
			//some logic
		}, this);
	}
}, this);

 

Роман, приветствую,

А у вас проблема в подзапросе или в сортировке?

Есть в сортировке, то возможно вам поможет вот это: https://community.terrasoft.ru/questions/entityschemaquery-order

Если в подзапросе, то можно

1. Сделать один запрос, а в его колбэке (или в цикле foreach, если это C# сделать еще один запрос).

2. Судя по всему подзапрос можно заменить обычным джойном.

На клиенте? Тогда как-то так:

var esq = Ext.create("Terrasoft.EntitySchemaQuery", { rootSchemaName: "Activity" });
 
esq.addColumn("Account.UsrINN", "AccountINN");
var column = esq.addColumn("ModifiedOn");
column.orderDirection = Terrasoft.OrderDirection.ASC; //asc по modifiedOn
 
esq.rowCount=1; //top1
 
esq.filters.addItem(esq.createColumnFilterWithParameter(3, "Account.UsrINN", "7730616959")); //фильтр по INN
 
esq.getEntityCollection(function (result) {
	if (result.success && result.collection.getCount() > 0) {
		var item = result.collection.getByIndex(0);
		var INN = item.get("AccountINN");
		var modOn = item.get("ModifiedOn");
	}
}, this);

 

Мне кажется, тут сам SQL-запрос надо вывернуть наизнанку:

SELECT max(ModifiedOn) FROM Activity activity
left join Account account on activity.AccountId=account.Id 
WHERE account.UsrINN = '7730616959'

То есть получим запрос с одной колонкой и одним фильтром по прямой связи. Заодно вместо TOP 1 можно просто максимум при помощи addAggregationSchemaColumn. А затем фильтруем, применив createColumnFilterWithParameter к колонке «Account.UsrINN».

 

Спасибо большое, вариант Данилы работает, но

Затык как раз в том что мне нужно вывести именно список контрагентов(UsrINN), а уже к каждому из них привязать дату последней работы с активностью.

 

 

 

Судя по исходному вопросу, код контрагента известен и равен 7730616959, следовательно, в списке всегда будет одна строка. Если таких номеров несколько, можно получить этим кодом в цикле для каждого.

Это часть системы поиска дублей.

Контрагентов с одинаковыми инн в системе может быть много, но не у каждого из них могут активности. Основная задача вывести контрагентов, а дата последнего взаимодействия по активностям - это довесок.

ИНН:123

10 контрагентов, но у 5ти из них есть активности.

Если я сначала полезу в таблицу активности, то мне выведется на экран только 5ть контрагентов, а реально их 10.

В самом начале я указал именно тот SQL запрос, который нужно изобразить с помощью ESQ.

Конечно можно это сделать двумя циклами, но хочется понять можно ли это сделать одним запросом

 

Такое есть смысл делать на сервере. В классе Select можно делать почти то же, что в SQL-запросах, плюс дубли могут быть недоступны через ESQ из-за прав доступа текущего пользователя, а Select работает в обход них.

Последовский Роман,

А так?

var esq = Ext.create("Terrasoft.EntitySchemaQuery", { rootSchemaName: "Account" });
esq.addColumn("UsrINN");
esq.addAggregationSchemaColumn("[Activity:Account].ModifiedOn", 5, "MaxModifiedOn");
esq.filters.addItem(esq.createColumnFilterWithParameter(3, "UsrINN", "7730616959"));
esq.getEntityCollection(function (result) {
	if (result.success && result.collection.getCount() > 0) {
		result.collection.collection.each(function(item) {
			//some logic
		}, this);
	}
}, this);

 

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

Памятник поставить мало! Спасибо)

Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Коллеги всем доброго времени суток!
Столкнулся с такой проблемой:
Формируем запрос к БД через ESQ - http://prntscr.com/jj0e03
далее делаем выборку из сформированной коллекции - http://prntscr.com/jj0efz
Однако при выборке вылетает ошибка - http://prntscr.com/jj0et9
Смотрим как сформировался SQL  - http://prntscr.com/jj0fa1
При этом var esqSmsStatus = esq.AddColumn("SmsStatus").Name; равно http://prntscr.com/jj0ka4
Кто с таким сталкивался? Прошу помочь.
Заранее благодарю.

У меня такой же вопрос

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

Недавно вроде отвечал на подобный вопрос. Попробуйте esq.AddColumn("SmsStatus.Id").Name. 

Чисто опытным путём было выяснено, что простые колонки и колонки, до которых можно просто добраться (пример: колонка Status, справочная. добавляем в запрос - esq.AddColumn("Status"). берём в результатах - p.GetTypedColumnValue<Guid>("StatusId") или p.GetTypedColumnValue<string>("StatusName")). Грубо говоря имеет смысл обозначать через Name только сложные пути, а-ля "Lead.QualifiedContact.Department.Name"

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

Благодарю!

В серверном коде при работе с этой функцией перед Id нет точки:

Page.DataSource.ActiveRow.GetTypedColumnValue<Guid>("AccountId"));

Отображаемое значение справочного поля тоже получается без точки:

entity.GetTypedColumnValue<string>("FacilityName");

 

Войдите или зарегистрируйтесь, чтобы комментировать