перебор всех записей датасета
Технические вопросы
Разработка

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

Необходимо перед добавлением\изменением записи детали проверить - не попадает ли заданный диапазон дат новой записи в один из уже существующих диапазонов записей датасета, а затем еще присвоить новой записи идентификатор таблицы реестра.

Я попытался сделать это на событие dlDataOnDatasetBeforePost в форме редактирования записи детали (wnd_SubContactPeriodsEdit)

var SubContactPeriodsDates = new Object();
...
function dlDataOnDatasetBeforePost(Dataset, DoPost) {

        // проверка на пересечение нового периода с существующими
        SubContactPeriodsDates.periodFrom = edtPeriodFrom.DataField.ValAsDateTime;
        SubContactPeriodsDates.periodTo   = edtPeriodTo.DataField.ValAsDateTime;

        Dataset.GotoFirst();
        while (!Dataset.IsEOF)
        {
                SubContactPeriodsDates.curFrom = Dataset.DataFields.ItemsByName('PeriodFrom');
                SubContactPeriodsDates.curTo   = Dataset.DataFields.ItemsByName('PeriodTo');
                if (intersectDate() )
                        {
                DoPost.Value = false;
                ShowErrorDialog('Заданный период пересекается с существующими!');
                return;
                        }
                Dataset.GotoNext();
        }

        Dataset.DataFields.ItemsByName('ManagerID').Value = SubContactPeriodsEdit.ParentItemID;
}
function intersectDate()
{      
        return ((SubContactPeriodsDates.curTo > SubContactPeriodsDates.periodFrom) &&
                        (SubContactPeriodsDates.periodTo > SubContactPeriodsDates.curFrom)) ? true:false;              
}

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

из идей только - воспользоваться dlDataOnDatasetAfterPost + Dataset.cancel()

Нравится

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

Как-то у вас тут все туманно. Почему даты в функцию не отдаете, а используете контролы как посредника?
И проверка странная...
Так как-то логичнее:
[javascript]
(periodFrom >= curFrom) && (periodTo <= curTo)

[/javascript]

Ну вобщем, да на BeforePost не надо ходить по датасету. Как вариант - это создавать еще один экземпляр, но я бы лично делал эту проверку одним sql-запросом типа :
[sql]
select count(1)
....
where
StartDate <= :startDate AND DueDate >= :dueDate
[/sql]
если вернет 0 - то можно постить.

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

Создайте сервис SelectQuery с необходимым запросом.
потом в коде на BeforePost берите его экземпляр, устанавливаете параметры
sq.Parameters.ItemsByName('StartDate') = periodFrom;
sq.Parameters.ItemsByName('DueDate') = periodFrom;
(Пишу по памяти - проверяйте)

Потом sq.Open() вернет датасет и у него смотрите значения поля, которое собственно и считает количество записей.

Только исправьте: для записи в параметр select query нужно писать SelectQuery.Parameters.ItemsByName('...').Value = ...

спасибо за помощь, у меня получилось вот так:
[javascript]
var SubContactPeriodsEdit= new Object();
...
function dlDataOnDatasetBeforePost(Dataset, DoPost) {

SubContactPeriodsEdit.periodFrom = edtPeriodFrom.DataField.ValAsDateTime;
SubContactPeriodsEdit.periodTo = edtPeriodTo.DataField.ValAsDateTime;

// проверка на пересечение нового периода с существующими
if (intersectDate() )
{
DoPost.Value = false;
ShowErrorDialog('Заданный период пересекается с существующими периодами!');
return;
}

Dataset.DataFields.ItemsByName('ManagerID').Value = SubContactPeriodsEdit.ParentItemID;
}

function intersectDate()
{
var sq = Services.GetSingleItemByUSI('sq_SubContactPeriodsIntersect');
sq.Parameters.ItemsByName('From').Value = SubContactPeriodsEdit.periodFrom;
sq.Parameters.ItemsByName('To').Value = SubContactPeriodsEdit.periodTo;
var ds = sq.Open();
return (ds.DataFields.ItemsByName('ID').Value > 0)?true:false;

}
[/javascript]

параметры я передал через глобальный объект SubContactPeriodsEdit, был бы признателен за любые замечания.

"Каукин Владимир Константинович" написал:параметры я передал через глобальный объект SubContactPeriodsEdit, был бы признателен за любые замечания.

А зачем через глобальный объект, если можно вот так:
[javascript]
...
if (intersectDate(Dataset.ValAsDateTime('PeriodFrom'), Dataset.ValAsDateTime('PeriodTo')))
...
[/javascript]
и
[javascript]
function intersectDate(StartDate, DueDate)
{
...
}
[/javascript]
Так же как-то логичнее и кода меньше..

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

Спасибо за советы.

У меня появился еще 1 вопрос, есть запрос вида:
[sql]
SELECT
COUNT(CAST([tbl_SubContactPeriods].[ID] AS VARCHAR(38))) AS [ID]
FROM
[dbo].[tbl_SubContactPeriods] AS [tbl_SubContactPeriods]
LEFT OUTER JOIN
[dbo].[tbl_Contact] AS [tbl_Contact] ON [tbl_Contact].[ID] = [tbl_SubContactPeriods].[ManagerID]
WHERE(:From BETWEEN [tbl_SubContactPeriods].[PeriodFrom] AND [tbl_SubContactPeriods].[PeriodTo] AND
[tbl_SubContactPeriods].[ManagerID] = :ManagerID)
[/sql]
он работал правильно, пока я не добавил фильтр сравнения для выборки данных только для текущей записи в реестре ( вот эта строка [tbl_SubContactPeriods].[ManagerID] = :ManagerID )

Если я подставляю в субд правильные значения, то запрос работает:
[sql]
WHERE('05.04.2011' BETWEEN [tbl_SubContactPeriods].[PeriodFrom] AND [tbl_SubContactPeriods].[PeriodTo] AND [tbl_SubContactPeriods].[ManagerID] = '8C6AE091-B24D-42B2-BD2B-4AE2B72EDB8E')
[/sql]
,так же он работал в системе без этого фильтра сравнения.
Создаю запрос и передаю ему параметры вот так:
[javascript]
function intersectDateForOne(constFrom,selID)
{ debugger;
var sq = Services.GetSingleItemByUSI('sq_SubContactPeriodsIntersectForOne');
sq.Parameters.ItemsByName('From').Value = constFrom;
sq.Parameters.ItemsByName('ManagerID').Value = selID;
var ds = sq.Open();
var test = ds.DataFields.ItemsByName('ID');
return (ds.DataFields.ItemsByName('ID').Value > 0)?true:false;
}
[/javascript]

Проблема в следующем, запрос без добавленного фильтра должен вернуть 2, с фильтром - 1, проверил в субд, на практике же без фильтра - 2, с фильтром 0 :(
Дебаггером я прошелся по каждой строке кода, но ничего странного не нашел, все параметры передаются и устанавливаются в нужные значения, может быть я неверно передаю параметры в запрос и этим все ломаю?
sq.Parameters.ItemsByName('ManagerID').Value = selID;

constFrom (Data), selID (String) - подаются норм

Владимир, прежде всего, замените GetSingleItemByUSI на GetNewItemByUSI:
[javascript]
var sq = Services.GetNewItemByUSI('sq_SubContactPeriodsIntersectForOne');
[/javascript]
Если запрос по-прежнему вернет 0, включите профайлер перед вызовом var ds = sq.Open() и проверьте какой запрос идет в БД.

спасибо за помощь, разобрался

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