Связывание объектов Notesdocument

Kizarek86

Lotus team
20.07.2007
864
4
#1
Собственно проблема в чем:

Это некоторый кусок логики при самописном логировании

Есть агент вызываемый через Ajax под Web, в нем получаем (через GetDocumentByUNID) документ (DOC1) изменяем его (пока не сохраняем), передаем этот документ в некоторую функцию в библиотеке, в которой получаем (также через GetDocumentByUNID) этот же документ (DOC2).
Так вот как я понимаю, получается так что и в DOC1 и в DOC2 теперь хранится один и тот же документ, причем = DOC2.

Есть ли возможность избежать этого и иметь оба объекта и DOC1 (измененный агентом) и DOC2 тот же документ но агентом не низменный?
 

nvyush

Lotus team
22.04.2009
2 317
0
#3
М.б. поможет перед открытием DOC2 выполнить DOC1.UniversalID = "какое-то значение"
 

Kizarek86

Lotus team
20.07.2007
864
4
#4
Спасибо.
Помогло получение второго документа через представление.
Не очень красиво конечно, но с подменой ИД мне ещё меньше нравицо)
 

VladSh

начинающий
Lotus team
11.12.2009
1 276
6
#6
Помогло получение второго документа через представление.
Не очень красиво конечно, но с подменой ИД мне ещё меньше нравицо)
Через представление необязательно.
Можно взять БД другим методом. Например, если она была получена по пути, то взять по ReplicaiD и наоборот, док, полученный из этой БД будет другим.
И ещё способ (я чаще всего так делаю) сделать объектам NotesDatabase и NotesSession Delete, а потом взять заново, "инстансы" будут другими и док соответственно тоже будет другим.
 

TIA

:-)
Lotus team
15.05.2009
790
3
#7
И ещё способ (я чаще всего так делаю) сделать объектам NotesDatabase и NotesSession Delete, а потом взять заново, "инстансы" будут другими и док соответственно тоже будет другим
Есть неприятные побочные эффекты. Все документы, виды и пр., полученные из NotesDatabase тоже обнулятся. Более щедящий подход -- делать Delete переполучаемому документу.
 

nvyush

Lotus team
22.04.2009
2 317
0
#8
так ведь подмена ИД ведёт к созданию нового дока?!
получаем (через GetDocumentByUNID) документ (DOC1) изменяем его (пока не сохраняем)
Если не сохранять, то новый документ не создастся. Суть моего предложения — "испортить" юнид документа (разумеется, сперва сохранить оригинал в переменной или cfd-поле для последующего восстановления), чтобы открытие с диска не затирало документ. КМК, должно работать, но сам не проверял.
Delete doc в данном случае не поможет, т.к. "убьёт" документ в памяти, а он нам ещё нужен.
 

nvyush

Lotus team
22.04.2009
2 317
0
#9
Иллюстрация предложенного метода:
<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">
Код:
Sub Initialize
Const fakeUnid = "00000000000000000000000000000000"

Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc1 As NotesDocument
Dim doc2 As NotesDocument
Dim unid As String

Set db = session.CurrentDatabase
Set doc1 = db.CreateDocument
Call doc1.ReplaceItemValue("Field", "old value")
Call doc1.Save(True, True)
unid = doc1.UniversalID
Delete doc1
Set doc1 = db.GetDocumentByUNID(unid)
Call doc1.ReplaceItemValue("Field", "new value")
doc1.UniversalID = fakeUnid
Set doc2 = db.GetDocumentByUNID(unid)
doc1.UniversalID = unid
Print "doc1.Field=" + doc1.GetItemValue("Field")(0) + "; doc1.unid=" + doc1.UniversalID
Print "doc2.Field=" + doc2.GetItemValue("Field")(0) + "; doc2.unid=" + doc2.UniversalID
Call doc2.Remove(True)
End Sub
Можно завернуть в функцию вида:
Код:
Function getDocOnDisk(doc As Notesdocument) As Notesdocument
Const fakeUnid = "00000000000000000000000000000000"
Dim unid As String
unid = doc.UniversalID
doc.UniversalID = fakeUnid
Set getDocOnDisk = doc.ParentDatabase.GetDocumentByUNID(unid)
doc.UniversalID = unid		
End Function
<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">
Код:
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc1 As NotesDocument
Dim doc2 As NotesDocument
Dim unid As String

Set db = session.CurrentDatabase
Set doc1 = db.CreateDocument
Call doc1.ReplaceItemValue("Field", "old value")
Call doc1.Save(True, True)
unid = doc1.UniversalID
Delete doc1
Set doc1 = db.GetDocumentByUNID(unid)
Call doc1.ReplaceItemValue("Field", "new value")
Set doc2 = getDocOnDisk(doc1)
Print "doc1.Field=" + doc1.GetItemValue("Field")(0) + "; doc1.unid=" + doc1.UniversalID
Print "doc2.Field=" + doc2.GetItemValue("Field")(0) + "; doc2.unid=" + doc2.UniversalID
Call doc2.Remove(True)	
End Sub
Добавлено
Обнаружен побочный эффект — NoteID сбрасывается в 0, а он к сожалению read-only. Попытка сохранить модифицированный документ вызывает ошибку Notes error: Database already contains a document with this ID (UNID).
 

VladSh

начинающий
Lotus team
11.12.2009
1 276
6
#10
Есть неприятные побочные эффекты. Все документы, виды и пр., полученные из NotesDatabase тоже обнулятся.
Ага, то я, когда надо "чистый" объект (до всех изменений) вытянуть так делал.
Но и не все объекты там при Delete NotesDatabase чистятся, это была фича, я даже в коде всё вручную чищу, начиная с NotesDocument'ов и поднимаясь выше.

А сейчас так:
Код:
%REM
Function reloadDoc
Description: получение нового инстанса документа
%END REM
Static Function reloadDoc(ND As NotesDocument) As NotesDocument
Dim NDB As NotesDatabase

Server$ = ND.ParentDatabase.Server
RID$ = ND.ParentDatabase.ReplicaID
UNID$ = ND.UniversalID

Set NDB = New NotesDatabase("", "")
Call NDB.OpenByReplicaID(Server$, RID$)

Set reloadDoc = NDB.GetDocumentByUNID(UNID$)
End Function
 

nvyush

Lotus team
22.04.2009
2 317
0
#11
VladSh
Можно получить неприятный побочный эффект, если потребуется в одном скрипте получить документы с диска из разных баз. Впрочем, вероятность такой необходимости невелика.
Другим недостатком предлагаемой функции являются статичные локальные переменные (тогда уж объявить статичной только NDB).
 

VladSh

начинающий
Lotus team
11.12.2009
1 276
6
#12
nvy
По первому - траблов не встречал, хотя получаю таким образом доки именно из разных баз.
По второму - какие статичные локальные переменные? Они грохаются при выходе из функции, статичный только возвращаемый результат, который дополнительным параметром возвращать мне неудобно.
 

nvyush

Lotus team
22.04.2009
2 317
0
#13
Они грохаются при выходе из функции, статичный только возвращаемый результат, который дополнительным параметром возвращать мне неудобно.
Все переменные, объявленные внутри статической функции, являются статическими, т.е. их значения сохраняются между вызовами, в том числе база данных. Именно поэтому данная функция возвращает документ, а не пустоту. Попробуйте убрать Static в объявлении функции, и она начнёт возвращать Nothing. Попробуйте добавить в начало функции строку Print "UNID=" + UNID$ и вызовите функцию два раза подряд — в первом случае получите пустой unid, во втором — имеющий значение. Логичнее было бы внутри функции объявить статической только NDB (Static NDB As NotesDatabase).
Что касается первой проблемы, то она, кмк, может возникнуть, когда в ходе исполнения одного скрипта переоткрываются документы из разных баз. В этом случае после второго вызова NDB теряет значение первой базы и, соответственно, должен теряться первый полученный документ. Опытов не ставил, но уверен, что это будет так.

Добавлено Это действительно так, причём даже если брать второй документ из той же базы — NDB затирается и прощай первый документ. Можно добавить второй параметр типа NotesDatabase и передавать в функцию переменную, объявленную в вызывающей процедуре, в этом случае можно и от Static избавиться.
 

VladSh

начинающий
Lotus team
11.12.2009
1 276
6
#14
nvy
Всё верно, так и произошло.
Т.е. для 2-х и более документов в пределах одной базы все эти "конструкции" на катят. Для одного дока, чтобы его взять заново, достаточно.
 

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 598
275
#15
ну и в итоге, в общем случае - возвращаемся к варианту byKey :) ?!
 

VladSh

начинающий
Lotus team
11.12.2009
1 276
6
#16
ну и в итоге, в общем случае - возвращаемся к варианту byKey ;) ?!
В общем случае, да, - byKey
А в итоге (по условиям задачи) хватит и одинарной перезагрузки (мне, кстати этого всегда хватало), конечно лучше модифицировав, как предложил nvy :)
 

nvyush

Lotus team
22.04.2009
2 317
0
#18
Не, лучше функция nvy с подменой UNID
Если нужно сохранять doc1 — не лучше. Эксперименты показали, что подмена unid делает документ "новым", т.е. сбрасывает NoteID в "0", попытка сохранить документ под старым unid вызывает ошибку "Notes error: Database already contains a document with this ID (UNID)". Для сохранения изменений придётся либо предварительно удалять документ с диска, например, doc2.Remove(True) (и плодить окурки), либо копировать изменения в doc2 и сохранять его. В любом случае танцы с бубном. КМК, лучше использовать доработанный вариант функции от VladSh. Для себя решил взять на вооружение такой вариант:
Код:
Function getDocOnDisk(doc As NotesDocument, db As NotesDatabase) As NotesDocument
'возвращает сохранённый на диске документ doc, db — переменная для сохранения нового экземпляра бд
Set db = New NotesDatabase("", "")
Call db.OpenByReplicaID(doc.ParentDatabase.Server, doc.ParentDatabase.ReplicaID)
Set getDocOnDisk= db.GetDocumentByUNID(doc.UniversalID)
End Function