Как я могу получить значения полей при сохранении нового "Запроса на изменение"?
Пробовал вывести через код в обработчике btnOKOnClick формы редактирования:

var dataset = dlData.Dataset;
ShowInformationDialog(dataset.Values('Description'));

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

Нравится

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

Всё, вопрос снимается, был невнимателен.

К вашему скрипту должен быть подключен скрипт scr_WindowUtils и параметр функции ShowInformationDialog(Parameter) должен быть текстовым.

Не видел предыдущего сообщения.

"Кулак Олег" написал:К вашему скрипту должен быть подключен скрипт scr_WindowUtils и параметр функции ShowInformationDialog(Parameter) должен быть текстовым.

Там была ошибка в том, что я пытался вывести в диалог блобовское(byte) поле).
Олег, я здесь походил по сайту - не нашел нигде RSS-ленты, или просто списка новых сообщений из всех разделов форума. Оно вообще здесь есть? А то неудобно скакать по разделам, проверяя на обновления.

Справа в меню пользователя "Последние сообщения".

Проглядел, спасибо.

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

Здравствуйте.

Сделал свою форму редактирования справочника, по этому описанию. Но, в моем справочнике есть поля типа boolean, для которых я добавил на форму редактирования контрол CheckBox (можно и RadioButton). У этих контролов нет свойства DataField, следовательно нужно при сохранении как-то читать значения из этих контролов, и руками пихать их в сохраняемую строку датасета. Кто-нибудь реализовывал такое?

Нравится

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

Вам нужен BoolDataControl.

"Глова Сергей" написал:Вам нужен BoolDataControl.

Сергей, большое спасибо, заработало).

"Глова Сергей" написал:

Вам нужен BoolDataControl.


Использую BoolDataControl для трёх полей, а возможно ли использовать в форме checkbox, при клике на который автоматически ставятся галочки в полях BoolDataControl?

Здравствуйте, Максим.

Для автоматической установки галочек в соответствии с содержимым базы данных служит BoolDataControl. Поведение CheckBox можно отдельно описать в скриптах карточки, обращаясь к свойству IsChecked:

Пример:

if (Dataset('BoolFiled') == true){
  CheckBox.IsChecked == true;
}

"Alimova Anna" написал:

Здравствуйте, Максим.

Для автоматической установки галочек в соответствии с содержимым базы данных служит BoolDataControl. Поведение CheckBox можно отдельно описать в скриптах карточки, обращаясь к свойству IsChecked:

Пример:

if (Dataset('BoolFiled') == true){

  CheckBox.IsChecked == true;

}

С уважением, Анна Алимова

Специалист II линии технической поддержки Terrasoft


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

Попробуйте CheckBox.IsChecked = true

Уточните, пожалуйста, как у Вас называется элемент управления чекбокс?

В каком месте программного кода Вы пытаетесь добавить проверку? Объявлена ли там переменная датасета?

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

Пытаюсь решить следущую задачу - автоматическое добавление дат выхода газеты при нажатии на кнопку.
Заполняется поле "Дата начала", "Количество выходов" и поле "Через номер"(да/нет), и при нажатии на кнопку "Подсчет" в таблицу "Даты выхода" добавляются необходимые даты, удаляются(если есть)даты не из этого диапозона и пропускаются даты которые уже есть.
Проблема возникает при попытке удаления большого количества дат, т.е. курсор при помощи dataset.Delete() доходит до конца выборки из сорока записей и пытаясь удалить следущую запись вызывает исключение.
Вот так это происходит:

function Button1OnClick(Control) {
        var vihdataset=wndvihGridArea.Window.ComponentsByName('dlData').Dataset;
        var InvoiceID=dlData.Dataset.ValAsGUID('ID');
        DataGridView = wndvihGridArea.Window.ComponentsByName('grdData').Items(0);
        wndvihGridArea.Window.ComponentsByName('grdData').ActiveView=DataGridView;
    column = DataGridView.Items(0);
        column.OrderType=otAsc;
        column.OrderPosition = 1;
        var SelectQuery = vihdataset.SelectQuery;
        column=SelectQuery.Columns.ItemsByAlias('dat');
        column.OrderType=otAsc;
        column.OrderPosition = 1;
        //количество выходов
        var kol=dlData.Dataset.ValAsInt('kol');
        RefreshDataset(vihdataset);
    //Дата начала
        var dat=new Date(dlData.Dataset.ValAsDateTime('Dat1'));
    //Массив содержаший все необходимые даты выхода
        var dats = new Array();
        var vihDates="";
        for (var i = 0; i kol; i++){
        //текстовое представтение всех необходимых дат выхода
                vihDates=vihDates+((i==0)?" ":", ")+DatToStrV(dat);    
                //
                dats.push(new Date(dat).getVarDate());
                //Добавляем 7 либо 14 дней к дате в зависимости от  значения поля "Через номер"
                dat=new Date(AddDateDays(dat,7*((!dlData.Dataset.ValAsInt('ChN')>0) ? 1 : 2)));
        }
        //Массив с уже имеющимися датами
        var datIn = new Array();
        //Если в Датасете ds_vih уже есть данные обрабатываем их...
        if (vihdataset.RecordsCount>0){
                vihdataset.GotoFirst();
                var rc=vihdataset.RecordsCount;

        for (var i = 0; i rc; i++){
        // функция GetIndexOfItemInArrayV возвращает индекс даты в массиве дат
        //вот ее код:
        /*function GetIndexOfItemInArrayV(SearchValue, SearchArray) {
    if (SearchArray.length==0){
            return -1;
    }
        for (var i = 0; i SearchArray.length; i++) {
        if (SearchValue-SearchArray[i]==0) {
            return i;        
        }
    }
    return -1;
   }*/

            //если значение поля dat не в массиве  необходимых дат выхода или оно уже в массиве  с уже имеющимися датами..
                if ((GetIndexOfItemInArrayV(vihdataset.ValAsDateTime('dat'), dats)==-1)||(
                                GetIndexOfItemInArrayV(vihdataset.ValAsDateTime('dat'), datIn)!=-1)){
                 //то удаляем эту запись
                                vihdataset.Delete();
                        }
                else{
                //иначе добавляем ее в в массив с уже имеющимися датами
                        datIn.push(vihdataset.ValAsDateTime('dat'));
                        vihdataset.GotoNext();
                        }
                }
        }      
        //массив с новыми датами
        var datNew = new Array();
        for (var i = 0; i kol; i++){
        //добавляем в него даты из массива содержашего все необходимые даты выхода, которых нет в массиве  с уже имеющимися датами
                if (GetIndexOfItemInArrayV(dats[i], datIn)==-1){
                datNew.push(dats[i]);
                }
        }      
        //Добавляем новые даты в ds_vih
        if (datNew.length>0){
        for (var i = 0; i datNew.length; i++) {
                        vihdataset.Append();
                        vihdataset.ValAsGUID('InvoiceID') = InvoiceID;
                        vihdataset.ValAsDateTime('dat') = new Date(datNew[i]).getVarDate();
                        vihdataset.Post();
                }
        }
        RefreshDataset(vihdataset);
        return;
}

Нравится

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

Попробуйте установить свойство FetchRecordsCount равным -1 перед открытием датасета.

Но в этом случае Вам придётся заменить первый вызов функции RefreshDataset на такую конструкцию:

vihdataset.Close();
vihdataset.FetchRecordsCount = -1;
vihdataset.Open();

И, возможно, вместо второго вызова аналогичным способом опять установить размер выборки равным 40.

Спасибо Вам огроменное, Олег!
Я часа 3 бородил по форуму, в поисках решения, а все оказывается так просто.:( :)
Нужно внимательней читать мануал.

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

Необхідна ця функція, щоб працювати з даними відібраними користувачем. Достатньо просто передати посилання на датасет.
Зауважу, потрібно ще підключити scr_WindowUtils і scr_Processings.

Використовую цю функцію:

 

function WriteFieldValueToDataset(Dataset, FieldName, FieldValue) {
       
        var ProgressBar = new Object;
       
        ProgressBar.Caption = 'Внесення змін';
        ProgressBar.Prompt = ' Виконується...';
        ProgressBar.Window = System.EmptyValue;
       
        var DatasetCount = Dataset.RecordsCount;
        var OldFetchSetting = Dataset.FetchRecordsCount;
        var StartCount = DatasetCount;
        var i = 0;
               
        BeginProcessingProgress(ProgressBar.Window, ProgressBar.Caption,
          ProgressBar.Prompt, true, false);

        Dataset.DisableEvents();
        Dataset.FetchRecordsCount = -1;
        RefreshDataset(Dataset);
       
        Dataset.GotoFirst();
        while (!Dataset.IsEOF){
                Dataset.Edit();
                Dataset(FieldName) = FieldValue;
                Dataset.Post();
                Dataset.GotoNext();
                var ProgressWindow = MoveProcessingProgress(ProgressBar.Window,
                  (i++)*100/StartCount, true);
                if (ProgressWindow.Attributes('CancelledByUser')) break;
        }
       
        Dataset.FetchRecordsCount = OldFetchSetting;
        RefreshDataset(Dataset);
        Dataset.EnableEvents();

        EndProcessingProgress(ProgressBar.Window, true);
}

Мав проблему з тим, що датасет по замовчуванню вибирає частину записів. Тому потрібно тимчасово виконати:

    Dataset.FetchRecordsCount = -1;
    RefreshDataset(Dataset);

А потім повернути старе значення. Інакше будуть "тормоза".

Дякую, Денису Масалову за вчасну пораду!

Нравится

Поделиться

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

Юрий, а почему не выполнить UpdateQuery с фильтрами, которые используются для открытия DataSet?
1. Это ускорит работу обновления на порядок - не надо будет "гонять" данные на клиент
2. А как Вы откатываете изменения? Почему без транзакции? Получается часть данных пользователь изменил, а часть нет. Это может привести данные в противоречивое состояние. А в случае UpdateQuery это исключено, так как будут обновлены сразу все или не одной записи.

1. Давайте спробуєм, ви можете викласти функцію, яка б збирала дані фільтру для будь-якого датасету і використовуючи відповідний автиматично створюємий UpdateQuery датасета для зміни значення поля всім відфільтрованим записам?
2. Зміни не відміняються, а припиняються. На скільки я розумію транзакція виконується при зміні кожного запису.

1. В случае если у Вас фильтры по Join в DBDataset, то такое нельзя будет сделать, в остальных реально. Главное использовать метод AssignObject, который скопирует за Вас всю структуру фильтров и параметров.
2. Правильно, если Вы не указали явно, то каждая операция с БД выполняется в рамках неявной транзакции. но если Вы сделаете старт транзакции явно, то все операции будут выполняться в рамкой Вашей транзакции и Вы сможет откатить все изменения или подтвердить их.

Дякую, Олександр, за корисний комент. Обов'язково врахую при необхідності.

К слову, зачем копировать фильтры, если можно пройтись по набору, собрать ИДшники записей в этом наборе и послать запрос вида

update table set ...
where ID in ( ... )

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

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

Тем, кому лень дизайнить сервисы для несложной выборки, посвящается.
Развивая тему, описанную мною здесь, можно получать набор данных, используя сервис, прикрепленный к этому посту (см. вложение), и следующую функцию:

function GetDatasetBySQL(sql) {
    var sq = Services.GetNewItemByUSI('sq_Select');
    sql = sql.replace('select', '');
    var sqlWithoutTop = '';
    if ((sql.indexOf('top') != -1) && (sql.indexOf('top') 10)) {
        sqlWithoutTop = Trim(sql.replace('top', ''));
        sqlWithoutTop = sqlWithoutTop.substring(sqlWithoutTop.indexOf(' '), sqlWithoutTop.length);
    }
    var FindFrom = 'from';
    var FromArray = (sqlWithoutTop == '') ?
        sql.split('from') :sqlWithoutTop.split('from');
    if (FromArray.length > 0) {
        FindFrom = 'from' + FromArray[FromArray.length - 1];
    }
    var SQLColumns = (sqlWithoutTop == '') ?
        Trim(sql.substring(0, sql.indexOf(FindFrom))).split(',') :
        Trim(sqlWithoutTop.substring(0, sqlWithoutTop.indexOf(FindFrom))).split(',');
    var Columns = sq.Items(0).Columns;
    var ColCount = SQLColumns.length;
    for (var i = 0; i ColCount; i++) {
        if (!Assigned(Columns.ItemsByAlias(SQLColumns[i]))) {
            var NewCol = Columns.CreateConstColumn();
            var NewColAlias = SQLColumns[i];
            NewColAlias = (NewColAlias.indexOf(' as') != -1) ?
                NewColAlias.substring(NewColAlias.indexOf(' as') + 3,
                    NewColAlias.length) : NewColAlias;
            NewCol.ColumnAlias = Trim(NewColAlias);
            Columns.Add(NewCol);
        }
    }
    Columns.ItemsByAlias('SQLColumn').SQLText = sql + '/*';
    var ds = sq.Open();
    return ds;
}

Использовать эту функцию можно так:
var Prefix = (Connector.CurrentUser.IsAdmin) ? 'tbl_' : 'vw_';
var sql =
        "select Name " +
        "from " + Prefix  + "Contact " +
        "where not AccountID is null " +
        "group by Name " +
        "having not Name like '%test%' " +
        "order by Name asc ";
var Dataset = GetDatasetBySQL(sql);
Log.Write(1, Dataset('Name'));

Поддерживается использование агрегатных функций, только в этом случае нужно обязательно дать полям выборки алиасы:
var Prefix = (Connector.CurrentUser.IsAdmin) ? 'tbl_' : 'vw_';
var sql =
        "select count(Name) as test " +
        "from " + Prefix  + "Contact ";
var Dataset = GetDatasetBySQL(sql);
Log.Write(1, Dataset('test'));

"+": экономия времени, не нужно особо ничего дизайнить.
"-": не предусмотрены сложные конструкции запросов с подзапросами, с exists-фильтрами и т.д. Поэтому рекомендую использовать в более простых случаях (или же доработать функцию своими силами).

Нравится

Поделиться

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

Стас, чего-то сбилось форматирование...
1. Я не увидел где ты работаешь с фильтрами Where, сортировкой Order by и группировкой Group By.
2. Непонятно почему ты создаешь Const колонки, а не General.
А так идея хорошая, сам когда-то порывался сделать :) , но учитываю сложность написания sql - парсера, пока забросил эту затею.

Стас, можно попробовать парсер от mssql - MSSQLParser.dll (это ActiveX библиотека), он правда очень простой, но "допилить" его можно, он и под Oracle работает. Он разбирает sql на составляющие - пример
И я еще не очень уверен, что его можно просто так ставить клиентам... но попробовать можно :)

>>1. Я не увидел где ты работаешь с фильтрами Where, сортировкой Order by и группировкой Group By.
>>2. Непонятно почему ты создаешь Const колонки, а не General.

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

По поводу парсера - попробую.

>>не очень уверен, что его можно просто так ставить клиентам
Это чисто "проектный" функционал, поскольку вся ответственность на разработчике и его "прямых" руках. А так, почему бы и нет... :)

Не понял :) Ты парсишь текст запроса и строишь SelectQuery, так вот не видно где ты фильтры добавляешь.... Или это только набросок и скрипт так сказать для "затравки"? :)

Нет, это вся функция. Попробую объяснить:
- сначала проверяю наличие top-а
- далее нахожу ту часть, которая идет после from-а.
Все это нужно просто для того, чтобы получить список колонок (т.е. секцию select-а).
А потом в первую CustomSQL-колонку прописываю весь запрос целиком, со всеми группировками, сортировками, фильтрами. И строю const-колонки для того, чтобы можно было корректно что-то вообще получать из датасета. В итоге получается запрос вида:

SELECT
	 Name as test from tbl_Contact where not AccountID is null group by Name having not Name like '%test%' order by Name asc /* AS [SQLColumn],
	*/
if 1=0
select getdate() AS [Fake],
	N'' AS [test]
FROM
	[dbo].[tbl_AccountGroup] AS [tbl_AccountGroup]

Помнишь такое? Это ж твоя была когда-то идея... :)

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

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

Та да )) я вот только увидел строчку

Columns.ItemsByAlias('SQLColumn').SQLText = sql +  '/*';

сразу понятно стало ;).

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Теперь понял... я было подумал, что ты написал простенький парсер sql...

Забыл прикрепить вложение. :(
Сейчас уже сообщение полноценное.

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

Вы не правы, намного проще написать в конфигурации, что-то типа:

var selectQuery = ConvertToSelectQuery("select Name from Table1");

которое, потом скрипт преобразует в универсальный формат, который уже будет выполняться на 3-х СУБД.

Стас, в прикрепленном сервисе SQL-запроса не хватает следующего SQL-кода для поля Fake:

*/
IF 1=0
SELECT getdate()

Прикрепил исправленный запрос.

Еще столкнулся с тем, что, когда я передаю в функцию SQL-запрос вида:

select distinct OwnerID
from tbl_OrderOffering

у меня в результате формируется датасет с именем поля 'distinct OwnerID'.

Чтобы формировалось правильное имя поля OwnerID, нужно заменить строчку в функции GetDatasetBySQL(sql)

var NewColAlias = SQLColumns[i];

на строчку

var NewColAlias = SQLColumns[i].replace('distinct', '');

Можно учесть и другие варианты кроме слова distinct.

Стас, спасибо за ценный материал.
Вопрос: проводилось ли исследование предложенного способа на ресурсоемкость? Имеется в виду время создания сервиса и выполнения запроса, по сравнению с традиционным задизайненным запросом в SelectQuery?

>>Кошкаров Андрей
Спасибо, Андрей, за Ваши наблюдения и комментарии. Извините за задержку с ответом, был в отпуске. Действительно, в этом варианте получения датасета не учтен ряд опций, таких как distinct и другие. В принципе, об этом я и предупреждал: "не предусмотрены сложные конструкции запросов с подзапросами, с exists-фильтрами и т.д. Поэтому рекомендую использовать в более простых случаях (или же доработать функцию своими силами)". :)

>>Гамора Дмитрий
Дима, такого анализа я не делал, так как основная идея была не быстродействие получения экземпляра, а простота работы метода.

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

Здравствуйте,

(TSCRM 3.2, MSSQL Server 2008)

При открытии датасета ds_MPlan.Open() в профайлере отлавливается запрос, который возвращается несколько строк, но ds_MPlan.RecordsCount при этом равен 0.
Если дело не в версии SQL Server, как тогда справиться с этой проблемой?

...
ApplyDateFilter(ds_MPlan, 'ShowsDate', StartShow.getVarDate(), EndShow.getVarDate());
        ApplyDatasetFilter(ds_MPlan, 'ScreenID', ScreenID, true);  
        ds_MPlan.Open();
        ShowInformationDialog(ds_MPlan.RecordsCount);
...

// На SQL Server 2005 работает. И на 2008 работало до какого-то момента.

Нравится

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

Количество записей в датасете ds_MPlan.PageRecordsCount. Может стоит им пользоваться.
ds_MPlan.RecordsCount шлет еще один запрос типа
select count(*) from (select ...)

А Вы запросы выполняете под одним пользователем?

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

А вот эти два запроса
1)Который идет на Open
2)Который идет на RecordsCount в середине select count(*) from (...)
они одинаковые?

да, и при этом запрос на RecordsCount возвращает нормальное число, а не 0.

Да ну, не бывает такого :)

Берем первый запрос на Open. Он ничего не возвращает. Дописываем в начало
select count(*) from (
и в конец
)
Выполняем. Получаем значение отличное от 0. Так у Вас получается?

Я бы еще поверил что какой-то запрос неправильно генерится террасофтом. Но так выходит мегабага в MSSQL.

Сами в это не можем поверить.

Не совсем так. Запрос, посланный на Open, возвращает значения, но если его в MSSQL запустить;
а датасет при этом пустой почему-то.
Связи сервисов в терасофте проверены сто раз.

Один и тот же код на 2005 сервере нормально отрабатывает, а на 2008 вот такое чудо :(

А, так MS честно работает. Это, наверное, компоненты доступа к нему подглючивают.
Разве TS совместим с 2008 MSSQL? Я думал только 2000 и 2005

официально не поддерживается. наверно он и дает сбои.

Добавлю свои комментарии:

Мы тестировали 3.3.0 и 3.3.1 с MS SQL 2008 - проблем не было замечено.

В одном из наших проектов клиент купил MS SQL 2008 и ТС 3.2.1.14 - с январе 2009г. ошибок со стороны MS SQL 2008 не было замечено!

--
www.it-sfera.com.ua
Terrasoft Solution Partner

Может это зависит от конкретной машины? MDAC, допустим, не тот.

"Kat" написал:// На SQL Server 2005 работает. И на 2008 работало до какого-то момента.

Меня смущает последняя строчка... Значит что-то изменилось...

--
www.it-sfera.com.ua
Terrasoft Solution Partner

а посмотреть, какой запрос приходит на сервер в Profiler?

Все оказалось совсем просто: было запущено два терасофта, смотрящие на разные базы, поэтому сервер БД путался.

всем спасибо ;)

+1

Бывает :) У меня однажды фильтр забыли отключить по-умолчанию... 3 часа рыли где проблема ;)

--
www.it-sfera.com.ua
Terrasoft Solution Partner

"Kat" написал:сервер БД путался

Так это все его происки :)

Со всеми наверное было. Да, когда по ошибке правишь в одном месте , а тестишь в другом на чинаешь верить в потусторонние силы и высший разум :)

"Kat" написал:Мы тестировали 3.3.0 и 3.3.1 с MS SQL 2008 - проблем не было замечено.

MSSQL 2008 поддерживается официально, начиная с версии 3.3.1. Были замечены проблемы при соединении с базой из Vista (64-бита) и Windows Server 2008 (32-бита). Сейчас разбираемся.

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

Добрый день!

Имеется следующий код:

       //...
var SelectQuery = Services.GetNewItemByUSI('sq_ReelInBlock');
ApplySelectQueryFilter(SelectQuery, 'BlockID', BlockID, true);
ApplySelectQueryFilter(SelectQuery, 'ReelTypeID', ReelTypeCommercial, true);
var ds_CurReelsInBlock = SelectQuery.Open();
        //...

затем идет обработка этого датасета и новые данные записываются в MemoDataset.
Мне необходимо до обработки данных добавить еще один элемент в датасет ds_CurReelsInBlock. Если применить Append и Post, будет ли новая запись датасета занесена в таблицу БД? Мне нужно этого избежать.

Заранее благодарю!

Нравится

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

Будет. Можно подвязаться на событие OnBeforePost и запрещать пост. Но как по мне нужно делать совсем по другому. Опишите задачу, может что-нибуть придумаем.

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