Имя: Пароль:
1C
1C 7.7
v7: Рассчитать хэш документа
0 Андрюха
 
25.10.11
05:51
Сделал через перебор значений реквизитов через метаданные, складываю в список значений сначала общие, потом шапку, потом построчно табличную часть. Полученный список значений преобразовываю во внутренню строку и получаю ее хэш МД5. Аналогично рассчитывается и хэш элементов справочников-реквизитов документа. Всё отлично, только всё считается долго, хотелось бы побыстрее.

Функция глПолучитьХэшДокумента(Док)

   Вид = Док.Вид();

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

   Для Сч = 1 По Метаданные.Документ(Вид).РеквизитШапки() Цикл
       
       Реквизит = Метаданные.Документ(Вид).РеквизитШапки(Сч).Идентификатор;
       Значение = Док.ПолучитьАтрибут(Реквизит);
       
       ТабРекв.НоваяСтрока();
       ТабРекв.Реквизит = Реквизит;
       ТабРекв.Значение = Значение;
       
   КонецЦикла;

   Док.ВыбратьСтроки();
   Пока Док.ПолучитьСтроку() = 1 Цикл
       Для Сч = 1 По Метаданные.Документ(Вид).РеквизитТабличнойЧасти() Цикл
           Реквизит = Метаданные.Документ(Вид).РеквизитТабличнойЧасти(Сч).Идентификатор;
           Значение = Док.ПолучитьАтрибут(Реквизит);
           
           ТабРекв.НоваяСтрока();
           ТабРекв.Реквизит = Реквизит;
           ТабРекв.Значение = Значение;
           
       КонецЦикла;
   КонецЦикла;
   
   СписокРеквизитов = СоздатьОбъект("СписокЗначений");
   ТабРекв.ВыбратьСтроки();
   Пока ТабРекв.ПолучитьСтроку() = 1 Цикл

       Значение = ТабРекв.Значение;
       
       Если (ПустоеЗначение(Значение) = 1) ИЛИ (Значение = Док)  Тогда
           Продолжить;
       КонецЕсли;
       
       Тип = ТипЗначения(Значение);
       
       Если Тип = 11 Тогда
           Спр = СоздатьОбъект("Справочник." + Значение.Вид());
           Если Спр.НайтиЭлемент(Значение) = 1 Тогда
               Значение = глПолучитьХэшЭлементаСправочника(Спр.ТекущийЭлемент());
           Иначе
               Продолжить;
           КонецЕсли;
           
       ИначеЕсли Тип = 12 Тогда
           Если ПустоеЗначение(Значение.Хэш) = 1 Тогда
               Док = СоздатьОбъект("Документ");
               Если Док.НайтиДокумент(Значение) = 1 Тогда
                   ТекХэш = глПолучитьХэшДокумента(Док.ТекущийДокумент());
                   Док.Хэш = ТекХэш;
                   Док.Записать();
                   Значение = Док;
               Иначе
                   Продолжить;
               КонецЕсли;
           КонецЕсли;
           Значение = Значение.Хэш;
       КонецЕсли;
       
       
       СписокРеквизитов.ДобавитьЗначение(Значение);
       
   КонецЦикла;

   Сервис = СоздатьОбъект("Сервис");
   Хэш = Сервис.ПолучитьХэшМД5(ЗначениеВСтрокуВнутр(СписокРеквизитов));
   
   Возврат Хэш;
   
КонецФункции
1 lamme
 
25.10.11
05:56
посмотри Formex
там вроде есть процедура рассчета md5
2 lamme
 
25.10.11
05:57
а .. ну да - ты вроде через него и получаешь
пардон
3 Андрюха
 
25.10.11
06:02
Пока читал нашел косяк в функции - передаваемый параметр Док и создаваемый объект Док, в случае, когда реквизит тоже документ.
4 skunk
 
25.10.11
06:05
для чего такой изврат?
5 Андрюха
 
25.10.11
06:07
Чтобы при открытии документа не важно когда сохраненного не записывать (проводить) его опять.
6 skunk
 
25.10.11
06:08
а что модифицированость уже не устраивает?
7 skunk
 
25.10.11
06:09
тем более что можно получить ид документа
8 Андрюха
 
25.10.11
06:11
Да, модифицированность в ряде случаев устраивает. А ИД документа - он же не изменится если я количество изменю на 1?
9 skunk
 
25.10.11
06:15
нет не изменется, он для уникальности ... а в каких случаях модифицированость  не помогает ...
10 skunk
 
25.10.11
06:16
или это рисуешь лог измененией ... чего меняли в документах?
11 VladZ
 
25.10.11
06:20
(0)  1. Почему бы не заменить конструкцию

Док.ВыбратьСтроки();
   Пока Док.ПолучитьСтроку() = 1 Цикл

на ВыгрузитьТабличнуюЧасть?


2. Теперь кусок...

ТабРекв.ВыбратьСтроки();
   Пока ТабРекв.ПолучитьСтроку() = 1 Цикл

       Значение = ТабРекв.Значение;
       
       Если (ПустоеЗначение(Значение) = 1) ИЛИ (Значение = Док)  Тогда
           Продолжить;
       КонецЕсли;
       
       Тип = ТипЗначения(Значение);
       
       Если Тип = 11 Тогда
           Спр = СоздатьОбъект("Справочник." + Значение.Вид());
           Если Спр.НайтиЭлемент(Значение) = 1 Тогда
               Значение = глПолучитьХэшЭлементаСправочника(Спр.ТекущийЭлемент());
           Иначе
               Продолжить;
           КонецЕсли;
           
       ИначеЕсли Тип = 12 Тогда
           Если ПустоеЗначение(Значение.Хэш) = 1 Тогда
               Док = СоздатьОбъект("Документ");
               Если Док.НайтиДокумент(Значение) = 1 Тогда
                   ТекХэш = глПолучитьХэшДокумента(Док.ТекущийДокумент());
                   Док.Хэш = ТекХэш;
                   Док.Записать();
                   Значение = Док;
               Иначе
                   Продолжить;
               КонецЕсли;
           КонецЕсли;
           Значение = Значение.Хэш;
       КонецЕсли;
       
       
       СписокРеквизитов.ДобавитьЗначение(Значение);
       
   КонецЦикла;

Это, конечно, надежно... Почему бы не сделать проще: полученную таблицу ТабРекв сохраняем в строку. Строку - хэшируем.

Всяко должно быть быстрее.
12 Андрюха
 
25.10.11
06:26
(11) А если в табличной части есть Номенклатура, в которой только изменили комментарий?
13 skunk
 
25.10.11
06:28
(12)ну так отслеживай это при изменение комментария в самой номенклатуре ... а то тебе придется отлавливаться все доки ... в которых есть номенклатура и там логировать
14 Андрюха
 
25.10.11
06:33
(13) Ну да, верно говоришь
15 Андрюха
 
25.10.11
06:36
Хотя нет. Хэш ВСЕХ документов должен будет измениться, где есть эта номенклатура. Другое дело, что ПЕРЕСЧИТАТЬСЯ он должен только когда этот документ будут трогать.
16 VladZ
 
25.10.11
06:38
(15) Не усложняй... Изменилась номенклатура - это одно. Изменился документ - это другое...
17 Андрюха
 
25.10.11
06:40
Не-не. В номенклатуре может измениться какой-нибудь мегаважный реквизит, который влияет на регистры при проведении.
18 VladZ
 
25.10.11
06:40
(17) Раз пошла такая пьянка - хэшируй заодно и движения документа.
19 VladZ
 
25.10.11
06:45
+18 По аналогии с (11): движения -> в ТЗ. ТЗ в строку. По строке - хэш...
P.S. Гы-гы-гы..  Игла в яйце, яйцо в утке, утка в зайце...  :)
20 skunk
 
25.10.11
06:47
(17)и что теперь будешь все документы перепроводить?
21 Андрюха
 
25.10.11
06:48
(19) Движения регистрировать смысла нет. Задача - получить гарантированно уникальный хэш документа, в зависимости от совокупности текущих значений реквизитов объекта.
(20) Только в случае, когда будет осуществлена попытка записи документа с изменившемся хэшем.
22 VladZ
 
25.10.11
06:51
(21) Хэш нужен для каких целей?
23 skunk
 
25.10.11
06:52
(21)ну тогда вот тебе задача ... а что если в номенклатуре изменят реквизит объектного типа который так-же может повлиять на проведение документа ... то есть не выберут новый объект ... а именно изменят какой-то реквизит у этого объекта
24 Андрюха
 
25.10.11
06:52
Много применений, ну например чтобы не проводить повторно документ, который не был изменен.
25 Андрюха
 
25.10.11
06:53
(23) Думаю надо при расчете хэша документа просто брать хэш справочника, который будет расчитан при записи элемента.
26 skunk
 
25.10.11
06:53
а если тмц изменит не тот кто смотрит документ ... а кто-то другой ...
27 Андрюха
 
25.10.11
06:54
тогда аллах-акбар, тем более если давят "Записать"
28 skunk
 
25.10.11
06:54
(21)я имел ввиду ... зашел я в тмц ... изменил счет затрат ... записал ... при записи будешь все документы перепроводить?
29 Irbis
 
25.10.11
06:55
Пустое это все, часто проще исправить ошибку чем искать виноватых. Которые к моменту поиска могут уже благополучно уволиться.
30 Андрюха
 
25.10.11
06:56
(28) Все то не буду. Нажало некто "ОК" - в ПриЗаписи посмотрели текущий хэш по Контексту, сравнили с имеющимся - идентично, значит записывать/перепроводить не надо, просто закрыли форму и вуаля.
31 skunk
 
25.10.11
06:57
вообще нажимая кнопку провести ... пользователь как-бы считает что документ надо провести ... независимо от того решит программа его проводить или нет ...


а вот если он нажал отмена ... то он как-бы думает, что в документе ничего не должено изменяться ... независимо от того где и как изменилась тмц
32 Андрюха
 
25.10.11
06:59
(31) Да, соглашусь, но давят обычно сначала Провести, потом ОК, да если еще и ПриЗаписиПерепроводить(1), то имеем целых 3, а то и 4 проведения.
33 Андрюха
 
25.10.11
07:00
А так, надо проводить - провели, даже если сам документ не меняли, а только изменили ГлубинуКредита у Контрагента.
34 skunk
 
25.10.11
07:01
(32)после провести ... модифицированость в ноль ... если человек откроет тмц из табличной ... модифицированость в истину
35 Андрюха
 
25.10.11
07:02
(34) Да, это очень хороший вариант, но если ГлубинаКредита или КатегорияНоменклатуры была изменена, то перепроводить НАДО, даже если документ не менялся.
36 Андрюха
 
25.10.11
07:03
А так - открыли, 1С посмотрела - модифицированность на нуле, нахрена напрягаться...
37 skunk
 
25.10.11
07:08
(35)если я открыл тмц ... и изменил в ней что-то ... что не влияет на проведение ... но твой хэш по всем реквизитам изменился ... документ получается надо перепровести
38 Андрюха
 
25.10.11
07:11
Да. Но он бы и так перепровелся, без всех этих хэшей. Используя же хэш получаем бонус в виде исключения проведения документа больше чем 1 раз.
39 Андрюха
 
25.10.11
07:13
Накладные расходы на расчет хэша по метаданным всё равно не превышают расходы на проведение документа. Но всё равно хотелось бы его считать побыстрее.
40 VladZ
 
25.10.11
07:13
(38) А теперь раскладку по времени приведи. Сколько ты по-времени экономишь? Если, конечно, экономишь....
41 skunk
 
25.10.11
07:15
а теперь вопрос ... я уже намекал ... но думай

итак имеем тмц ... отнесеную на счетзатрат1 ... имеем около 5000 проведенных документов в разных периодах, в том числе и закрытых ...

что будет делать твоя программа когда я зайду в справочник и поставлю счетзатрат2

что будет делать твоя программа когда я из документа измению даный реквизит с другими 4999 проведенными документами...
42 VladZ
 
25.10.11
07:15
+40 Однако...  Отвечаешь быстрее, чем я спрашиваю..  :)
43 Андрюха
 
25.10.11
07:16
Хэш считается примерно 1,5 секунды и на клиенте (т.е. на вялом клиенте может достигать значения 2-2,5 сек.). А проведение одного документа с табличной частью 10 строк - 4 сек. (а есть документы и с гораздо большим количеством строк). Умножь его на 2 и добавь повышение возможности возникновения блокировок при (пере)провдении - вот тебе и гешефт.
44 Irbis
 
25.10.11
07:17
>> проведение одного документа с табличной частью 10 строк - 4 сек.
Не пора ли в консерватории что-то поменять? Может лучше оптимизацией кода заняться, чем всякими хэшами
45 Андрюха
 
25.10.11
07:18
(44) Пора конечно )))
46 Irbis
 
25.10.11
07:19
Так делай, а не ищи лишних приключений
47 Андрюха
 
25.10.11
07:20
(46) Хорошо.
48 Андрюха
 
25.10.11
07:21
(41) Программа будет в случае записи/проведения будет записывать/проводить этот документ, т.к. у него изменился хэш. Сейчас она итак записывает/проводит по требованию оператора. Количество записей/проведений может быть уменьшено, если реквизита документа не модифицировались.
49 Андрюха
 
25.10.11
07:24
проведение заявки из 216 строк - 10 секунд, (SQL, 30 пользователей), у кого меньше?
50 Мимохожий Однако
 
25.10.11
07:26
Занятная штука. Однако лучше обойти, чем вляпаться. Я бы шел по пути ограничения прав и включения режима просмотра документа с выключением кнопки.
51 Андрюха
 
25.10.11
12:30
во что вляпасться-то? сделай константо или хэшируй только большие документы с ТЧ > 100 поз
52 Злой Бобр
 
25.10.11
12:46
(0) Почитал ветку и так и непонял - нахрена? За что боремся? Или просто практикуемся от нечего делать?
53 Злопчинский
 
25.10.11
13:03
(49) проведение заявки или корректирующей заявки из 700-900 строк - порядка 1-2 сек
54 Злопчинский
 
25.10.11
13:36
не.. у меня тоже была идея такой эже хеш сделать.. потом подумал и отказался.. ну его на, проще это забороть административными методами и запретом изменений задним числом. Если изменения задним числом - норма - то надо что-то в консерватории менять, а если это эпизодические вынужденные действия - то проблем нет..
.
сделал в доке два реквизита:
Маркер1 и Маркер2
ПриЗаписи маркер1 пишется в маркер2, в маркер1 пишется изменено+дата+время+имяпользователя
при выгрузке дока в бухию маркеры сдвигаются аналогично, в маркер1 пишется выгружено+дата+время+имяпользователя.
.
маркер1 отображаю в титуле окна.
.
все, этого достаточно...