Getdocumentbyunid , если документ был удален

  • Автор темы wowa
  • Дата начала
T

TIA

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

Ну вот. Обсуждали, обсуждали, что GetDocumentByUNID всё равно надо заключать в функцию, обязательно имеющую обработчик. Т.к. в некоторых ситуациях GetDocumentByUNID бросает эксепшен и никакой проверки IsValid, IsArray выполнить уже не удастся.
Так что отсутствие обработчика -- не аргумент. Время выполнения doc.Items - операция сильно зависящая от количества и объёма полей.
Ладно, вот мои замеры. У документа 300 полей. Значение каждого поля -- строка из 16 байт. Каждая операция выполнялась 300 раз над одним и тем же документом.

=======================================
seconds % calls max.secs event
=======================================
00004,125 100,0% 0000001 00004,125 Total run time
00004,015 097,3% 0000001 00004,015 IsArray
00000,016 000,4% 0000001 00000,016 GetItemValue
00000,015 000,4% 0000001 00000,015 HasItem
=======================================

IsArray в 250 раз тормознее GetItemValue. Если учесть ещё распространённость вызовов GetDocumentByUNID -- существенная разница.


если не ведется обработка тысяч документов
Тысячи документов -- обычное дело для серверного агента.
 
A

Akupaka

хотя можно использовать и проверку на Universalid (он в этом случае = "")
нет, унид нормальный, на сколько помню

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

я предлагаю IsEmpty
думаешь, будет быстрее? :)
 
T

TIA

я предлагаю IsEmpty, хотя можно использовать и проверку на Universalid (он в этом случае = ""), но не люблю я стринги
Главное для производительности не IsEmpty или IsArray, а избавиться от doc.Items

а, если писать из головы, да и не принципиально, то можно и isarray
Иногда, в особых случаях, когда не принципиально, помолясь -- тогда можно :) Вобщем, уговорил.
 
T

TIA

думаю, да; хотя, возможно, и ошибаюсь

Замеры на 300 повторах (детали см. выше)

seconds % calls event
======================================
00008,422 100,0% 0000001 Total run time
00003,999 047,5% 0000300 IsArray(doc.Items)
00003,922 046,6% 0000300 IsEmpty(doc.Items)
00000,031 000,4% 0000300 GetItemValue("AnyItem")
00000,016 000,2% 0000300 HasItem("AnyItem")
 

VladSh

начинающий
Lotus Team
11.12.2009
1 797
158
BIT
230
TIA, спасибо, очень интересно!
Значит использовать проверку на пустоту UNID'а. Кстати, я как только увидел, что UNID = "", так сразу и понял, почему в наших старых скриптах при обходе документов коллекции была эта проверка :)
 
T

TIA

начит использовать проверку на пустоту UNID'а
Можно. Но необходимый и достаточный набор, это:

Код:
Function BadDocToNothing( doc as NotesDocument) as NotesDocument
'Конвертит doc в Nothing если он "кривой"
'Функция никогда не бросает эксепшен
On Error Goto ErrH
if False then
ErrH: Resume ErrQ
ErrQ: Exit Function
End if

if not doc.IsValid or not .IsDeleted then exit function
dim v
v = doc.AnyItem(0) ' обращение к любому полю. Кажется, Hasitem не всегда защищало. Нужно именно получение значения.

'опционально
'if doc.HasItem("$Conflict") or doc.ParentDocumentUNID = doc.UniversalId then exit function

Set BadDocToNothing = doc
End Function

Function GetDocByUNID(db as NotesDatabase, unid$) as NotesDocument
'Получение документа по UniversalId.
'Функция никогда не бросает эксепшен.
On Error Goto ErrH
if False then
ErrH: Resume ErrQ
ErrQ: Exit Function
End if

dim doc as NotesDocument
On Error Resume Next
Set doc = db.GetDocumentByUNID( unid )
On Error Goto ErrH
Err = 0

Set GetDocByUNID = BadDocToNothing( doc )
End Function
 
H

hosm

Модераторы, если можно, перенесите всё, что по обработке ошибок в отдельную тему! Думаю, подходящая тема где-то здесь есть ))
Обсуждение кода TIA (и обработки ошибок) перенесено сюда - link removed, начиная [post="159796"]с этого поста[/post], в который он процитирован полностью.
Более подходящей темы пока не нашла, смотрела еще в сторону этой темы - Когда имеет смысл ставить "on Error Resume Next", но там уже свое обсуждение завязалось, не хотелось влезать :rolleyes: Если у участников обсуждения есть претензии или лучшая тема - пишите в личку.

Насчет пустоты унида для недоступных док-тов - ранее (на 6ке) такого не припомню, но на 8.5 так и было (я выше переспрашивала в ветке), причем вроде взятие унида эксепшен не бросало, просто возвращало пустую строку.
VladSh А со стрингами какие проблемы-то, почему нелюбовь к ним? я еще поняла бы к вариантам, а со стрингами - для меня пока загадочно.

В эту тему может подойти еще замечание:
[quote date='5:02:2010 - 17:31']Речь шла о критериях валидности документа. Обработка эксепшена -- существенная часть проверки. Его конкретная реализация -- нет.[/quote]
 

VladSh

начинающий
Lotus Team
11.12.2009
1 797
158
BIT
230
А со стрингами какие проблемы-то, почему нелюбовь к ним? я еще поняла бы к вариантам, а со стрингами - для меня пока загадочно.
Уже о5 не по теме ))) Это бы в тему о скорости поместить (она была в прилепленных).

String, с нашего, "высокоуровневого", подхода, конечно, ничего ничего плохого не имеет. Но уже на уровне C - это массив символов, т.е. реально производится сравнение 2-х массивов перебором в цикле; операций получается очень много: для каждого символа, его надо сначала взять, а потом произвести сравнение.

Variant, наоборот, хорош тем, что может ничего не содержать. Я это использую, когда функция должна возвратить массив. Ещё с давних времён, самой быстрой проверкой считается, конечно эксепшн, и проверка указателем на Null, т.е. на пустое место. Аналоги IsNull(): IsEmpty() и Is Nothing. Уже медленнее работают IsScalar(), IsObject(), IsArray(), т.к. дополнительно ещё делают "предпроверку" типа.
 
F

fedotxxl

Написал 2 функции... Надеюсь нет ошибок и они кому-то пригодятся
Код:
Function checkNothing(value As Variant) As Boolean
On Error Goto errLab

If Not Isobject(value) Then Exit Function

Dim answer As Boolean
Dim nd As NotesDocument

Select Case Typename(value)
Case "NOTESDOCUMENT":
Set nd = value
answer = checkNothingDoc(nd)
Case Else: answer = value Is Nothing
End Select

checkNothing = answer
Exit Function

errLab:
Call LogErrorEx("", SEVERITY_HIGH, Nothing)
checkNothing = True 
Exit Function
End Function
Код:
Function checkNothingDoc(nd As NotesDocument) As Boolean
On Error Goto errLab
On Error 4 Goto err4 'обращение к любому полю. Кажется, Hasitem не всегда защищало. Нужно именно получение значения.

Dim answer As Boolean
Dim v As Variant

If nd Is Nothing Then
answer = True
Elseif (Not nd.IsValid) Or (nd.IsDeleted) Then 
answer = True
Else
v = nd.AnyItem(0) 'Если документ не валидные, то должна свалиться ошибка 'TODO отловить # ошибки
End If

checkNothingDoc = answer
Exit Function

errLab:
Call LogErrorEx("", SEVERITY_HIGH, Nothing)
checkNothingDoc = True 
Exit Function

err4:
checkNothingDoc = True 
Exit Function
End Function
При тестировании на строке nd.AnyItem(0) ошибка не вылетала... так что нужно этот момент (№ ошибки) доделать
 

VladSh

начинающий
Lotus Team
11.12.2009
1 797
158
BIT
230
fedotxxl
Надеюсь никому не пригодятся.

1. "Надеюсь нет ошибок" + "так что нужно этот момент (№ ошибки) доделать"...

2. Зачем каждый раз дёргать эту кучу кода??! Лучше в каждом случае использовать свои проверки.
- обычно достаточно проверки на Is Nothing;
- в случае получения документа (по UNID'у или при переборе коллекции) достаточно что-то типа IsDocAccessed;
- проверки на Not Isobject(...) в общих функциях говорят о том, что с Variant'ом переигрались.. Проверка такая нужна, но достаточно редко.

Кажется я начинаю понимать, что такое "высоконагруженные кодом базы данных"...
 
F

fedotxxl

VladSh
Ну давай друг друга покритикуем...

1. "Надеюсь нет ошибок" + "так что нужно этот момент (№ ошибки) доделать"...
Кода возникнет ошибка, Сработает обработчик errLab, функция вернет правильный результат, но залогирует ошибку в OpenLog. Потом нужно будет просто посмотреть номер ошибки в openLog'e и чуть-чуть переписать функцию

2. Зачем каждый раз дёргать эту кучу кода??! Лучше в каждом случае использовать свои проверки.
- обычно достаточно проверки на Is Nothing;
Тож всегда проверял на Nothing, но недавно напоролся на данную проблему
проверки на Not Isobject(...) в общих функциях говорят о том, что с Variant'ом переигрались.. Проверка такая нужна, но достаточно редко.
В функции checkNothing это оправдано - нету ведь базового класса object для объектов LotusNotes. В функцию checkNothingDoc можно было бы передавать notesDocument, тогда в checkNothing нужно было определить переменную, присвоить ей значение и передать уже переменную NotesDocument. Я так не сделал, т.к. код читался бы хуже
в случае получения документа (по UNID'у или при переборе коллекции) достаточно что-то типа IsDocAccessed;
Рассмотрим IsDocAccessed
Код:
Function IsDocAccessed(ND As NotesDocument, SetNothing As Boolean) As Boolean
If Not ND Is Nothing Then
If ND.IsValid And Not IsEmpty(ND.Items) And Not ND.IsDeleted Then	'Добавил проверку на Items, т.к. действительно бывают траблы; спасибо сообществу!
IsDocAccessed = True
Exit Function
End If
End If
If SetNothing Then Set ND = Nothing
End Function
Кода, действительно меньше, но работать он будет В РАЗЫ дольше, как уже писали выше. Во-первых, хотя бы сделать конструкцию if - elseif и поставить на верх ND.IsValid, ND.IsDeleted, а IsEmpty(ND.Items) в самый низ. Во-вторых лучше заменить IsEmpty(ND.Items) (хотя я здесь не могу утверждать до конца)

Добавлено:
Я так не сделал, т.к. код читался бы хуже
Хотя лучше переписать checkNothingDoc. Обновил
 
N

nvyush

Использую такой вариант:
Код:
Function GetDocumentByUNID(doc As NotesDocument, db As NotesDatabase, UNID As String) As NotesDocument
On Error Goto ErrorHandler
Set doc = db.GetDocumentByUNID(UNID)
If doc.IsValid And Not doc.IsDeleted Then
If doc.Size > 0 Then
Set GetDocumentByUNID = doc
Exit Function
End If
End If	
ExitFalse:
Set GetDocumentByUNID = Nothing
Exit Function
ErrorHandler:
Resume ExitFalse
End Function
Можно использовать конструкции вида
Код:
If GetDocumentByUNID(doc, db, UNID) Is Nothing Then Exit Sub
Или, если уверены в существовании документа
Код:
GetDocumentByUNID(doc, db, UNID).Remove 'и т.п.
 

VladSh

начинающий
Lotus Team
11.12.2009
1 797
158
BIT
230
Кода, действительно меньше, но работать он будет В РАЗЫ дольше, как уже писали выше.
Где такое писали, пример? /Спрашиваю именно о построении функции, а не о IsEmpty(ND.Items)/

Во-первых, хотя бы сделать конструкцию if - elseif и поставить на верх ND.IsValid, ND.IsDeleted, а IsEmpty(ND.Items) в самый низ.
Большого прироста производительности это не даст. Лично я не вижу смысла это делать, т.к. чтение кода усложняется. Тут - хозяин-барин.
Скоро, когда переедем на Java, это всё наоборот будет лишним, т.к. условие, записанное в строку, в нормальных языках вычисляется не целиком, а по частям.

Во-вторых лучше заменить IsEmpty(ND.Items) (хотя я здесь не могу утверждать до конца)
Да, лучше заменить, не спорю. До экспериментов ещё руки не дошли.
Но однозначно - я точно против проверки на ошибку, это хоть и быстрее всего, но здесь, по моему нагружать лишним обработчиком неуместно. Вот если бы не проверять на Nothing, тогда возможно.. - была бы полноценная альтернативная реализация ;)

Хотя лучше переписать checkNothingDoc. Обновил
Гораздо лучше.
А без checkNothing я бы обошёлся (не вижу её необходимости) - проверяю в каждом конкретном случае по своему.


Добавлено:
nvy
Вот эта реализация мне больше по душе :) У меня что-то похожее, только внутри ещё вызов IsDocAccessed.
Железно работает? Проверяли?
 
N

nvyush

Железно работает? Проверяли?
Проверял на 7.0.2 и 8.0.2 (с более древними не знаком, до более новых руки не дошли). Если документ не удалён, но у пользователя нет к нему доступа по ридерс полям, Size возвращает 0.
 
F

fedotxxl

А такой вопрос - проблемы с документом (объект возвращается, но не является вадным) возникают только при использовании функции db.GetDocumentByUNID ? Или же такая же проблема может возникнуть при использовании nv.getAllDocumentsByKey или каких-либо других ситуациях?
 
O

Omh

Или же такая же проблема может возникнуть при использовании nv.getAllDocumentsByKey или каких-либо других ситуациях?
Ну, по идее, всякие окурки и прочие невидимые по ридерасм документы во view не отображаются, следовательно в коллекцию не берутся.
Но брать из view - доолго.
Точнее брать из view не долго, а вот брать само view - expensive operation.

На истину не претендую.
 
F

fedotxxl

Omh
Тут идея в другом - нужна ли данная проверка всегда или же только на функцию GetDocumentByUNID
Ну по иджее всякие окурки и прочие невидимые по ридерасм документы во view не отображаются, следовательно в коллекцию не беруться.
В вид могут попадать документы, которые данные пользователь не видит
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!