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

Я попытался сделать это на событие 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 комментариев

Как-то у вас тут все туманно. Почему даты в функцию не отдаете, а используете контролы как посредника?
И проверка странная...
Так как-то логичнее:

(periodFrom >= curFrom) && (periodTo <= curTo)

Ну вобщем, да на BeforePost не надо ходить по датасету. Как вариант - это создавать еще один экземпляр, но я бы лично делал эту проверку одним sql-запросом типа :

select count(1)
....
where
StartDate <= :startDate AND DueDate >= :dueDate

если вернет 0 - то можно постить.

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

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

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

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

спасибо за помощь, у меня получилось вот так:

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;
 
}

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

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

А зачем через глобальный объект, если можно вот так:

...
if (intersectDate(Dataset.ValAsDateTime('PeriodFrom'), Dataset.ValAsDateTime('PeriodTo')))
...

и

function intersectDate(StartDate, DueDate)
{       
...
}

Так же как-то логичнее и кода меньше..

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

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

У меня появился еще 1 вопрос, есть запрос вида:

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)

он работал правильно, пока я не добавил фильтр сравнения для выборки данных только для текущей записи в реестре ( вот эта строка [tbl_SubContactPeriods].[ManagerID] = :ManagerID )

Если я подставляю в субд правильные значения, то запрос работает:

WHERE('05.04.2011' BETWEEN [tbl_SubContactPeriods].[PeriodFrom] AND [tbl_SubContactPeriods].[PeriodTo] AND [tbl_SubContactPeriods].[ManagerID] = '8C6AE091-B24D-42B2-BD2B-4AE2B72EDB8E')

,так же он работал в системе без этого фильтра сравнения.
Создаю запрос и передаю ему параметры вот так:

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;      
}

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

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

Владимир, прежде всего, замените GetSingleItemByUSI на GetNewItemByUSI:

var sq = Services.GetNewItemByUSI('sq_SubContactPeriodsIntersectForOne');

Если запрос по-прежнему вернет 0, включите профайлер перед вызовом var ds = sq.Open() и проверьте какой запрос идет в БД.

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

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