• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Lotus Script Как Проверить На Уникальность Поля?

  • Автор темы diga
  • Дата начала
D

diga

Lotus Script как проверить на уникальность поля?

имеется поле OrgID

для событии Querysave написал следующий скрипт:

Код:
Sub Querysave(Source As Notesuidocument, Continue As Variant)
Dim doc As NotesDocument
Set doc = source.Document
Dim db As NotesDatabase
Set db = doc.ParentDatabase
Dim ndc As NotesDocumentCollection
Dim var As String
If ( source.FieldGetText( "OrgTitle" ) = "" ) Then 
Messagebox( "Заполните поле наименование организации" )
Call source.GotoField( "OrgTitle" )
continue = False 
Else 
If ( source.FieldGetText( "OrgID" ) = "" ) Then
Messagebox( "Отсутствует краткое наименование организации" )
Call source.GotoField( "OrgID" )
continue = False
Else 
'var = doc.getItemValue("OrgID")(o)
Set ndc = db.Search("456", Nothing, 0)
numDocs& = ndc .Count
If (numDocs& >1) Then
Messagebox( "Такое краткое наименование существует!" )
Call source.GotoField( "Org ID" )
continue = False 
Else
Messagebox( "Данные успешно сохранены" )
End If
End If
End If
End Sub

не могу исправить ошибки, а именно как сделать так, чтоб при поиске "456" в результате выдавалась ошибка что такое имя уже существует. При этом надо проверить на условие что найденный документ (например если он нашел только одну) редактируемый данный документ или другой, если другой то выдать сообщение об ошибке. С помощью кода
Код:
var = doc.getItemValue("OrgID")(o)
хотел присвоить значения поля в переменную и уже производить поиск
Код:
Set ndc = db.Search(var, Nothing, 0)

Но выдает ошибку.

Буду рад любой помощи! Спасибо большое!
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
так-ссс...
1. db.Search для таких целей очень долго, не оправдано долго.
2. Неверная формула отбора, параметр var должен быть сформирован как формула отбора в представлении.
Пример: db.Search({Form = "MainTopic"}, Nothing, 0) тогда в ndc попадут все документы по форме MainTopic
3. Решение вопроса есть, да и не редкость.

Если вкратце:
1. Делаете служебное представление, в первую колонку вставляете вывод значения поля или ключа, по которому проверяете уникальность. У вас это OrgID.
2. Делаете эту колонку сортированной, это обязательно.
3. На событии QuerySave вешаем код, который по данной вьюхе получает коллекцию документов.
Set ndc = view.GetAllDocumentsByKey(doc.getItemValue("OrgID")(0), True)
Далее проверяем коллекцию и текущий документ по циклу:
Код:
'currDoc - текущий документ на экране
Set doc = dc.GetFirstDocument
While Not doc Is Nothing
If doc.UniversalID <> currDoc.UniversalID Then
Msgbox "Документ с таким названием уже существует.",16
Goto endh
End If
Set doc = dc.GetNextDocument(doc)
Wend
Есть минусы: если документы ограничены readers полями и пользователь не видит их - проверка не сработает.
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
178
если сделать исполнение кода под админом (проверки или редактором), а поля ридерс для них задавать в доках всегда (например ролями) - можно нивилировать минус
 
D

diga

1. Делаете служебное представление, в первую колонку вставляете вывод значения поля или ключа, по которому проверяете уникальность. У вас это OrgID.
2. Делаете эту колонку сортированной, это обязательно.

что - то это не совсем понял что тут делать? то есть у меня будет допустим представление: "Служебное" Как вы сказали сделаю вывод значения поля. Для чего мы его сортируем? и если сортировать то каким именно образом это сделать? как он будет влиять если не будет сортировки

Спасибо
 
H

hosm

>diga Для чего мы его сортируем? и если сортировать то каким именно образом это сделать
1) Для получения этого: Set ndc = view.GetAllDocumentsByKey(currdoc.getItemValue("OrgID")(0), True), где view - созданное представление, currdoc - текущий открытый док.
2) Любым, порядок сортировки колонки для данной задачи не имеет значения.
Остальные ваши вопросы обычно решаются путем вдумчивого прочитывания ответа savl и хелпа дизайнера (создание представления для отбора GetAllDocumentsByKey).
При очень больших проблемах в понимании - просите помощь "зала" - старших товарищей (вы же не единственный лотусист в организации?).
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
GetAllDocumentsByKey работает по первой сортированной колонке, по ней она будет искать документы. если колонка не будет сортирована, то функция ничего не вернет. Подробнее написано в help к дизайнеру.
В дизайнере, при создании представления, в свойствах колонки на второй закладке выставляется сортировка.
 
D

diga

Goto endh

что за команда? в хелпе не находит
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
хех)
Goto - это переход на метку, да в лотусе это есть)
endh - метка.

Goto Endh можно заменить на Exit Sub или Exit Function, все зависит где данная строка.
Так как это в QuerySave, то можно Exit Sub
 
D

diga

и так же как он понимает что именно по OrgID надо проверить уникальность?

создал структуру как посоветовали сортировал, но результата никакого
может я что то не дописал?

Код:
Sub Querysave(Source As Notesuidocument, Continue As Variant)
Dim doc As NotesDocument
Set doc = source.Document
Dim db As NotesDatabase
Set db = doc.ParentDatabase
Set doc = dc.GetFirstDocument
Dim ndc As NotesDocumentCollection
Dim var As String
If ( source.FieldGetText( "OrgTitle" ) = "" ) Then 
Messagebox( "Заполните поле наименование организации" )
Call source.GotoField( "OrgTitle" )
continue = False 
Else 
If ( source.FieldGetText( "OrgID" ) = "" ) Then
Messagebox( "Отсутствует краткое наименование организации" )
Call source.GotoField( "OrgID" )
continue = False
Else 
While Not doc Is Nothing
If doc.UniversalID <> currDoc.UniversalID Then
Msgbox "Документ с таким названием уже существует.",16
End If
Set doc = dc.GetNextDocument(doc)
Wend
Messagebox( "Данные успешно сохранены" )
End If
End If
End Sub

на
Код:
Goto endh
ругался пришлось убрать его.
Спасибо
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
Пичаль... Ничего в коде не смущает?
Set doc = dc.GetFirstDocument - убрать строку, зачем второй раз переопредляете объект, да еще и с ошибкой, объекта dc же нет.
может я что то не дописал?
Не дописал, получения документа из представления по GetAllDocumentsByKey.
Объект currDoc не инициализирован.
После Msgbox "Документ с таким названием уже существует.",16должно быть continue = False
После каждого continue = False надо ставить Exit Sub иначе документ все равно сохраняется.

Товарищ, данный код - не работает и будет выдавать ошибки. Не проверяли?
Стажер на обучении?
 
D

diga

Товарищ, данный код - не работает и будет выдавать ошибки. Не проверяли?
Стажер на обучении?



скорее практику прохожу в универе) дали кучу книг и задание, никакого обучения нет. вот и возникают некоторые трудности

Добавлено:
Товарищ, данный код - не работает и будет выдавать ошибки. Не проверяли?
Стажер на обучении?



скорее практику прохожу в универе) дали кучу книг и задание, никакого обучения нет. вот и возникают некоторые трудности
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
diga
"Некоторые трудности"...
0. Строим нормальный алгоритм, на бумаге. Сначала общий, затем подробнее.
1. Добавляем обработчик ошибок:
Код:
Sub Querysave(Source As Notesuidocument, Continue As Variant)
On Error Goto handler
Const FuncName = {Sub "Querysave" }
Dim ErrStr As String

' Ваш код

Goto Endh
handler:
ErrStr = FuncName & ": " & Err &", в стр " & Erl & nLine & Error$
Msgbox ErrStr, 16, "Error!"
Resume endh
Endh:
End Sub
2. Исправляем ошибки, чтобы они не возникали. Работать верно не будет, но главное поймете как их исправлять и что какая значит.
3. Читаем про объекты NotesDocument (получение/изменение полей, сохранения), NotesUIDocument (в частности события), NotesView (как получать документы), NotesDatabase (как получать представления). Книги надеюсь есть на русском? Help с нуля читать на английском трудно, сам проходил.
4. Применяем полученные знания к алгоритму для решения задачи.

Практика, практика, практика.
 
D

diga

Пичаль... Ничего в коде не смущает?
Set doc = dc.GetFirstDocument - убрать строку, зачем второй раз переопредляете объект, да еще и с ошибкой, объекта dc же нет.

Не дописал, получения документа из представления по GetAllDocumentsByKey.
Объект currDoc не инициализирован.
После Msgbox "Документ с таким названием уже существует.",16должно быть continue = False
После каждого continue = False надо ставить Exit Sub иначе документ все равно сохраняется.

Товарищ, данный код - не работает и будет выдавать ошибки. Не проверяли?
Стажер на обучении?
не могли бы вы помочь и написать правильную реализацию? Спасибо большое.
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
diga
Помочь могу, но писать не буду, тем более что это часть обучения.
Советы я написал, далее желание.
 
D

diga

diga
Помочь могу, но писать не буду, тем более что это часть обучения.
Советы я написал, далее желание.

Сделал следующим образом, все вроде как работает как надо.
Код:
Sub Querysave(Source As Notesuidocument, Continue As Variant)
Dim db As NotesDatabase 'переменная класса базы данных
Dim doc As NotesDocument 'переменная класса документ базы данных
Dim currDoc As NotesDocument 'переменная класса документ базы данных
Dim view As notesView ' класс вид
Dim ws As New NotesUIWorkspace 'текущий открытый документ
Dim ndc As NotesDocumentCollection 'переменная класса колекции документов
Set doc = source.Document 'получаем ссылку на текущий документ "заднего плана"
Set db = doc.ParentDatabase 'получаем ссылку на текущую БД
If ( source.FieldGetText( "OrgTitle" ) = "" ) Then 
Messagebox( "Заполните поле наименование организации" )
Call source.GotoField( "OrgTitle" )
continue = False 
Else 
If ( source.FieldGetText( "OrgID" ) = "" ) Then
Messagebox( "Отсутствует краткое наименование организации" )
Call source.GotoField( "OrgID" )
continue = False
Else 
Set view=ws.CurrentDatabase.Database.GetView("Main View")
Set currDoc=view.GetDocumentByKey(source.FieldGetText( "OrgID" ))
If (Not currDoc Is Nothing)  Then
Msgbox "Документ с таким названием уже существует.",16
continue = False
Exit Sub
End If
Messagebox( "Данные успешно сохранены" )
End If
End If
End Sub

то теперь возник другой вопрос, как теперь можно проверить уникальность в рамках одной формы? то есть, у нас имеется форма "организация", которая создает новую форму "подразделение" надо проверить уникальность поля "DepID" в форме "подразделение"в рамках организации. Как я понимаю в рамках организации это поле должно быть уникальна, но есть различные организации где могут быть подразделения с таким же названием. если же таким же методом
Код:
Set view=ws.CurrentDatabase.Database.GetView("Main View")
Set currDoc=view.GetDocumentByKey(source.FieldGetText( "DepID" ))
то получаем все DepID во всех организация. Каким образом сделать так чтоб он проверял именно в текущей Организации, несмотря на то что мы находимся в форме Подразделение? Спасибо.
 
T

ty3uk

UPD: Переправил ответ полностью....
1) в вашем алгоритме, при повторном сохранении документа будет в 100% случаев выдавать что такая организация уже существует! (выше приводиться алгоритм, который проверяет найденый документ на соотвествие UniversalID документа). Подправте данный момент...
+ для GetDocumentByKey, крайне рекомендуется, второй параметр, ставить в true
2) по второму, уже написали ответ...
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
160
diga
молодец) Но ошибки логики все же есть, не все советы видимо внял.
Ну ничего страшного, ниже немного модифицированная версия. Проверять не проверял, но думаю без особых ошибок будет.
Лучше проверять документы на уникальность в цикле, тут много причин. почему так лучше.
И да, обработчик ошибок - нужен и должен быть написан самым первым, иначе черт ногу сломит при поиске ошибок.

По поводу подразделений: можно проверять точно также, только ключ поиска изменится.
А вот как измениться надо подумать. Можно оставить одну колонку и сделать составной ключ: OrgID + {~} + DeptID и искать по нему.
А можно сделать 2 колонки (вторую тоже надо отсортировать) и посылать уже 2 ключа для поиска.
Код:
dim sKey(1) as variant
sKey(0) = source.FieldGetText( "OrgID " )
sKey(1) = source.FieldGetText( "DeptID " )
Set nDc = view.GetAllDocumentsByKey(skey, true)

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">модифицированная версия</div></div><div class="sp-body"><div class="sp-content">
Код:
Dim db As NotesDatabase 'переменная класса базы данных
Dim doc As NotesDocument 'переменная класса документ базы данных
Dim currDoc As NotesDocument 'переменная класса документ базы данных
Dim view As notesView ' класс вид
Dim ws As New NotesUIWorkspace 'текущий открытый документ
Dim ndc As NotesDocumentCollection 'переменная класса колекции документов

Set doc = source.Document 'получаем ссылку на текущий документ "заднего плана"
Set db = doc.ParentDatabase 'получаем ссылку на текущую БД
If ( source.FieldGetText( "OrgTitle" ) = "" ) Then 
Messagebox( "Заполните поле наименование организации" )
Call source.GotoField( "OrgTitle" )
continue = False 
Exit sub
End if
If ( source.FieldGetText( "OrgID" ) = "" ) Then
Messagebox( "Отсутствует краткое наименование организации" )
Call source.GotoField( "OrgID" )
continue = False
Exit sub
End if

Set view=ws.CurrentDatabase.Database.GetView("Main View")
Set nDc = view.GetAllDocumentsByKey(source.FieldGetText( "OrgID" ),true)
If nDc.Count > 1 then
Set currDoc= ndc.GetFirstDocument
Do While not currDoc is nothing
if currDoc.UniversalID <> doc.UniversalID then
Msgbox "Документ с таким названием уже существует.",16
continue = False
Exit Sub
end if

Set currDoc= ndc.GetNextDocument(currDoc)
Loop
End if
Messagebox( "Данные успешно сохранены" )
 
H

hosm

>Set view=ws.CurrentDatabase.Database.GetView("Main View")
так получать БД не надо. Есть ньюансы с CurrentDatabase. Лучше из документа (или из сессии, если это текущая БД) Set db вы сделали просто так, для увеличения кол-ва строчек? ;)
 
Мы в соцсетях:

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