Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Мой первый класс, укажите на грабли (число прочтений - 4321 )
koreav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 3
Зарегистрирован: 13. Января 2008
Мой первый класс, укажите на грабли
20. Марта 2011 :: 09:40
Печать  
Задача: переопределить метод "ВыбратьПодчиненныеДокументы"

объявление:
class Документ2005 =  sql2005.ert : Документ
{

};





сам класс:

Перем ПодменятьВызов;                  // в соответствии с настройками конфигурации
Перем ПодменаАктивна;                  // была получена выборка подчиненных по новому алгоритму

Перем Выборка;                              // таблица с выбранными документами
Перем ВыборкаТекСтрока;                  // текущая позиция в выборке
Перем ВыборкаРазмер;                  // кол. документов в выборке
Перем ВыборкаОбратныйПорядок;      // порядок сортировки по датам

Процедура УстановитьТекущийДокумент(Документ)
     
     я().ПолучитьБазовыйКласс().НайтиДокумент(Документ);
     
КонецПроцедуры

Функция ВыбратьПодчиненныеДокументы_ToySQL(ДатаНач,ДатаКон,ДокументРодитель)
     
     Запрос = СоздатьОбъект("ToyQuery");
     
     Запрос.Вернуть1С = 1;
     
     ТекстВыполнения = "
     |select [Ж.Ссылка] Докум
     |from [Подчиненные] ПД with(nolock)
     |inner join [Журнал] Ж with(nolock) ON [ПД.ДокументИд] = [Ж.ДокументИд]
     |where [Родитель] = [@ДокументРодитель]";
     
     Если ПустоеЗначение(ДатаНач) = 0 Тогда
           ТекстВыполнения = ТекстВыполнения + "
           |and [Ж.ДатаДок] >= [@ДатаНач]";
     КонецЕсли;
     
     Если ПустоеЗначение(ДатаКон) = 0 Тогда
           ТекстВыполнения = ТекстВыполнения + "
           |and [Ж.ДатаДок] <= [@ДатаКон]";
     КонецЕсли;
     
     ТекстВыполнения = ТекстВыполнения + "
     |order by [Ж.ДатаВремяИд]" + ?(ВыборкаОбратныйПорядок=1," desc","");

     Если Запрос.МетаЗапрос(ТекстВыполнения)=0 Тогда
           Сообщить(Запрос.Ошибка);
           Возврат 0;
     КонецЕсли;
     
     Запрос.Выгрузить(Выборка);
     Запрос.Закрыть();
     Запрос = 0;
     
     ВыборкаРазмер = Выборка.КоличествоСтрок();
     ВыборкаТекСтрока = 0;
     
     Если ВыборкаРазмер > 0 Тогда
           // в соответсвии со штатным методом установим курсор на первый документ
           УстановитьТекущийДокумент(Выборка.ПолучитьЗначение(1,"Докум"));
           Результат = 1;
     Иначе
           Результат = 0;
     КонецЕсли;
     
     Возврат Результат;
     
КонецФункции

/
// Служебные функции
/

Функция _ПолучитьКод() Экспорт
     
     Возврат Строка(я().ПолучитьБазовыйКласс());
     
КонецФункции

Процедура Конструктор()
     
     Если (глТой = 1) И (Константа.РежимРаботыБД = Перечисление.РежимыРаботыБД.SQL2005) Тогда
           ПодменятьВызов = 1;
     Иначе
           ПодменятьВызов = 0;
     КонецЕсли;
     
     ПодменаАктивна = 0;
     
     Выборка = СоздатьОбъект("ТаблицаЗначений");
     ВыборкаТекСтрока = 0;      
     ВыборкаРазмер = 0;      
     ВыборкаОбратныйПорядок = 0;
     
КонецПроцедуры


/
// Переопределенные методы
/

Функция ВыбратьПодчиненныеДокументы(ДатаНач,ДатаКон,ДокументРодитель) Экспорт
     
     Если ПодменятьВызов = 0 Тогда
           Возврат одитель);
     Иначе
           ПодменаАктивна = 1;
           Возврат ВыбратьПодчиненныеДокументы_ToySQL(ДатаНач,ДатаКон,ДокументРодитель);
     КонецЕсли;
     
КонецФункции

Функция ПолучитьДокумент() Экспорт
     
           Если (ПодменятьВызов = 0) ИЛИ (ПодменаАктивна = 0) Тогда

           Возврат я().ПолучитьБазовыйКласс().ПолучитьДокумент();
     Иначе
           
           ВыборкаТекСтрока = ВыборкаТекСтрока + 1; // нумерация с 1
           
           Если ВыборкаТекСтрока > ВыборкаРазмер Тогда
                 Результат = 0;
           Иначе
                 Выборка.ПолучитьСтрокуПоНомеру(ВыборкаТекСтрока);
                 УстановитьТекущийДокумент(Выборка.Докум);
                 Результат = 1;
           КонецЕсли;
           
           Возврат Результат;
           
     КонецЕсли;
     
КонецФункции

Функция ОбратныйПорядок(НовыйРежим) Экспорт
     
     // учтем это для обоих механизмов
     
     ВыборкаОбратныйПорядок = НовыйРежим;
     
     Возврат я().ПолучитьБазовыйКласс().ОбратныйПорядок(НовыйРежим);
     
     
КонецФункции

  
Наверх
 
IP записан
 
Satans Claws
God Member
*****
Отсутствует


1C++ rocks!

Сообщений: 721
Зарегистрирован: 29. Ноября 2010
Re: Мой первый класс, укажите на грабли
Ответ #1 - 21. Марта 2011 :: 05:20
Печать  
1) ПодменаАктивна переключившись в 1 не меняется до конца жизны объекта
2) Соответственно, ВыбратьПодчиненныеДокументы(), а затем ВыбратьДокументы() (и любое другое открытие штатной выборки) сделает поведение объекта радикально отличающимся от обычного объекта Документ.
3) Метод ОбратныйПорядок() не влияет на твой обход подчиненных документов

Ну и приватная переменная ВыборкаТекущаяСтрока - все элементарно реализуется и без нее.
  
Наверх
 
IP записан
 
koreav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 3
Зарегистрирован: 13. Января 2008
Re: Мой первый класс, укажите на грабли
Ответ #2 - 21. Марта 2011 :: 09:20
Печать  
1+2) Это, да. Т.е. нужно переопределить все методы открывающие выборку, можно ли сделать это как-нибудь красиво, т.к. код у них всех (кроме ВыбратьПодчиненныеДокументы) будет одинаковый:

Код
Выбрать все
ПодменаАктивна = 0;
я().ПолучитьБазовыйКласс().ПереопределяемыйМетод_ххх(); 



?

3) Почему? я же сортирую при выборке данные:
Код
Выбрать все
   ТекстВыполнения = ТекстВыполнения + "
     |order by [Ж.ДатаВремяИд]" + ?(ВыборкаОбратныйПорядок=1," desc",""); 




Цитата:
Ну и приватная переменная ВыборкаТекущаяСтрока - все элементарно реализуется и без нее.

Согласен.

Еще немного волнующих вопросов:

1) нужно ли реализовывать функции Сам(), Этот()? Или это все устарело, и нужно для совместимости с другими классами?
2) функции я() и вирт(): я так понимаю они возвращают Контекст, я правильно использовал я(), или нужно было писать вирт()?
3) Функция конфы, которая перестала работать с моим классом Документ2005:
Код
Выбрать все
Процедура ПометитьНаУдалениеПодчиненные(Докум)
	ПДок = СоздатьОбъект("Документ");
	ПДок.ВыбратьПодчиненныеДокументы(,,Докум); [b]<-- вот тут 1С неявно использует Докум.ТекущийДокумент(), а мой класс нет[/b]
	Пока ПДок.ПолучитьДокумент() = 1 Цикл
		Попытка
			ПДок.Удалить(0);
		Исключение
			Предупреждение("Один или более подчиненных документов на удаление НЕ помечены! ("+ПДок+")");
		КонецПопытки;
		ПометитьНаУдалениеПодчиненные(ПДок);
	КонецЦикла;
КонецПроцедуры
 


т.е. вопрос:
по аналогии с функцией
Код
Выбрать все
Функция _ПолучитьКод() Экспорт
     Возврат Строка(я().ПолучитьБазовыйКласс());
КонецФункции
 


интуитивно чуствую что должна быть предопределенная функция типа:
Код
Выбрать все
Функция _ПолучитьОбъект() Экспорт
     Возврат я().ПолучитьБазовыйКласс().ТекущийДокумент();
КонецФункции 



4) Как правильно писать:
Код
Выбрать все
я().ПолучитьБазовыйКласс().НайтиДокумент(Документ); 


или
Код
Выбрать все
я().НайтиДокумент(Документ); 



и спасибо за помощь нубу Улыбка
  
Наверх
 
IP записан
 
Satans Claws
God Member
*****
Отсутствует


1C++ rocks!

Сообщений: 721
Зарегистрирован: 29. Ноября 2010
Re: Мой первый класс, укажите на грабли
Ответ #3 - 21. Марта 2011 :: 12:18
Печать  
Если мне не врет протез, то метод ОбратныйПорядок() работает следующим образом:

Открыли выборку.
Сделали сколько-то шагов по выборке.
Сделали ОбратныйПорядок(1).
Сделали сколько-то шагов в обратном направлении.
Сделали ОбратныйПорядок(0)
Снова идем в прямом направлении.

Вызов метода ОбратныйПорядок() до открытия выборки указывает, будем ли мы спозиционированны перед первой или после последней записи в выборке.


По поводу функции Сам() и Я()
Не знаю, может, конечно, сейчас допилили 1С++ и сделали функцию Я() прямо в движке 1С++, но раньше функции вида Сам() писали из-за той фичи 7.7, что Контекст можно передать только как параметр в какую-либо функцию/процедуру/метод.
Просто обратиться к контексту (например Контекст.Форма) - нельзя.
Для этого и писали
Код
Выбрать все
Функция Сам(Конт) Возврат Конт КонецФункции. 


Где ее писать - абсолютно без разницы.
У меня она написана в глобале.


По поводу Я().НайтиДокумент() и Я.ПолучитьБазовыйКласс().НайтиДокумент() - эти 2 вызова решают абсолютно разные задачи.
Во втором случае - ты принудительно передаешь управление классу-родителю
В первом - ты принудительно передаешь управление созданному объекту.
А текущее исполнение кода может находиться где-то посередине.
На примере, чтоб было понятно:
Есть Класс ТДокумент, наследующий от Документ
Есть Класс ТДокумент.РасходнаяНакладная, наследующий от ТДокумент.
В классе ТДокумент есть такой метод:
Код
Выбрать все
Функция Записать() Экспорт
Сам = Сам(Контекст);
Если Сам.ПроверитьПередЗаписью() <> 1 Тогда
возврат 0;
КонецЕсли

АвторПоследнегоИзменения = глПользователь;
Сам.ПолучитьБазовыйКласс().Записать();
КонецФункции 



теперь ты создаешь объект ТДокумент.РасходнаяНакладная, и после каких-то действий вызываешь Объект.Записать();
Если в классе ТДокумент.РасходнаяНакладная метод Записать() переопределен - выполнится он.
Если нет - то выполнится метод Записать() у ТДокумент. Этот метод вызовет функцию проверки у ТДокумент.РасходнаяНакланая (а если его нет - то у его родителя, т.е. у себя - будем считать, что у ТДокумент он существует. Причем, в ТДокумент.РасходнаяНакладная метод ПроверитьпередЗаписью() может сам принудительно вызывать этот же метод у базового класса).
И если проверка прошла успешно - вызовется метод Записать базового класса Документ (т.е. непосредственно документа 1С), который зафиксирует изменения в базе.
Таким образом, мы можем разделить проверки и действия при записи по уровням наследования.

Если же ты в ТДокумент напишешь просто
Код
Выбрать все
Если ПроверитьПередЗаписью() <> 1 Тогда
возврат 0;
КонецЕсли
 


то вызовется только метод класса ТДокумент и если он пройдет успешно - документ запишется в базу.
  
Наверх
 
IP записан
 
koreav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 3
Зарегистрирован: 13. Января 2008
Re: Мой первый класс, укажите на грабли
Ответ #4 - 23. Марта 2011 :: 09:28
Печать  
С методом ОбратныйПорядок() потом, при написании самотестирования, разберусь.



С контекстом теперь ясно. Не буду заморачиваться, использование Я() вполне устраивает.
Цитата:
По поводу Я().НайтиДокумент() и Я.ПолучитьБазовыйКласс().НайтиДокумент() - эти 2 вызова решают абсолютно разные задачи.


Вот они - скрытые грабли, теперь их вижуУлыбка Неправильно я использовал этот метод, например в функции:

Код
Выбрать все
Процедура УстановитьТекущийДокумент(Документ)
     я().ПолучитьБазовыйКласс().НайтиДокумент(Документ);
КонецПроцедуры
 




ПолучитьБазовыйКласс() абсолюно лишнее.
  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать