Странности лотуса...

  • Автор темы fedotxxl
  • Дата начала
F

fedotxxl

Вот такой код
Код:
Public docReq As NotesDocument


.....


Set agent = awfec.db.GetAgent(AgentName)
Call awfec.docReq.Save(True, True)

Call agent.RunOnServer(awfec.docReq.NoteID)

Dim ViewUNID As NotesView
Set ViewUNID = awfec.db.GetView("(AWF_CustomID)")

Set awfec.docReq = ViewUNID.GetDocumentByKey(awfec.docReq.AWF_CustomID(0))
В последней строке однажды произошла ошибка Type Mismatch. Как такое может быть? Я понимаю, если object variable not set....
 

Medevic

Что это ? :)
Green Team
10.12.2004
3 334
1
BIT
6
А что странного? Число или дата в поле AWF_CustomID даст, наверное, такую ошибку. :)
Извиняюсь, сглючил. Думал там GetDocumenByID. ;)
 
D

D!m@n

1. Что такое awfec?
2. awfec.docReq.AWF_CustomID(0) - точно строка?
3. awfec.docReq - точно или NotesDocument, или Variant?
 
S

sanch

попробуй так Set awfec.docReq = ViewUNID.GetDocumentByKey(cstr(awfec.docReq.AWF_CustomID(0)),True)
 
S

SkinGreek

сегодня столкнулся с подобной ошибкой, правда она была устойчивой...
суть была следующая...
есть функция
Код:
DDGetReferencedDoc(DDocID As String, DDLIBRARY As Variant) As Notesdocument
Она написана разработчиками Dom.Doc'a
мой агент ее юзал следующим образом

Код:
	Set DDdoc = dstBinder.Documents.Add
...
DDdoc.save
Call DDdoc.SetToWorkingCopy
Dim DDProfileDoc As NotesDocument	
Set DDProfileDoc = DDGetReferencedDoc(DDdoc.Id, library)
...
код падал с ошибкой Type Mismatch, на следующей строке внутри функции
Код:
Set ReferencedDDoc = DDLIBRARY.GetDocumentByID (DDocID)
при этом в документации написано было что DDdoc.Id возвращает String
если этот же код вызывать в агенте то все было ок, если передавать необходимые для этого параметры функии - выдавал ошибку.
помок совет sanch
Код:
Set DDProfileDoc = DDGetReferencedDoc(cstr(DDdoc.Id), library)
Но, ИМХО, это чушь какая-то до сих пор не смог понять "полу типизации" LS'a:((
 
S

SkinGreek

сегодня лотус меня одаривает своими причудами...
вот что я делаю не так?
Код:
	Dim AAA As NotesDocument
Set AAA = DDGetReferencedDocForDDoc(DDdoc)
Print "BEFORE"
If AAA Is Nothing Then
Print "AAA Is Nothing !!!"
End If
Dim BBB As NotesDocument	
Set BBB = DDGetReferencedDoc(main.DDDocumentID(0), library)
Print "AFTER"
If AAA Is Nothing Then
Print "AAA Is Nothing !!!"
End If
выводит следующее
Код:
BEFORE
AFTER
AAA Is Nothing !!!
функция DDGetReferencedDoc использует DDGetReferencedDocForDDoc но мне кажеться это не важно.
глобальных переменных не юзаю

Гуру объясните неразумному плз, каким образом вот эта строка
Код:
Set BBB = DDGetReferencedDoc(main.DDDocumentID(0), library)
виляет на локальную переменную AAA?
 
K

K-Fire

Думаю следующий сценарий происходит:
DDGetReferencedDocForDDoc(DDdoc) возвращает NotesDocument, а для этого внутри функции (вернее библиотеки) определяется некая переменная NotesDatabase.
Второй вызов каким-то образом "убивает" переменную NotesDatabase, в результате становится Nothing и уже возвращенный NotesDocument.
 
S

SkinGreek

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

Вот код обоих функций, в них нет ничего что могло бы повлечь такое поведение

Код:
Function DDGetReferencedDoc(DDocID As String, DDLIBRARY As Variant) As Notesdocument
On Error Goto errorhandler

Dim ReferencedDDoc As Variant 
Set DDGetReferencedDoc = Nothing

'Get Domino.Doc Reference using ID
Set ReferencedDDoc = DDLIBRARY.GetDocumentByID (DDocID) 'DocumentID(0))  
Set DDGetReferencedDoc = DDGetReferencedDocForDDoc(ReferencedDDoc)

Exit Function

errorhandler: 
Select Case Err
Case 213:
Error 21043, gWFSession.GetText("DDDocDocNA")'"The referenced Domino.doc document cannot be located"
Case Else
Error Err, Error$	 
End Select
Exit Function

End Function

Function DDGetReferencedDocForDDoc(DDoc As Variant) As Notesdocument
Dim docUnID As String 
Dim cabinet As Variant 
'CabinetDb is defined globally, otherwise the document referrence retrieved from this objekt will deleted this function terminates
Dim DBReplicaID As String
Dim binder As Variant
Dim serverName As String 

'get DocumentUniqueID
DocUnID = DDoc.UniversalId

'get DatabaseReplicaID
Set binder = DDoc.Binder  'get parent binder
DbReplicaID = binder.DocumentDatabase ' get replica ID of database

'get ServerName
Set cabinet = binder.cabinet ' get parent cabinet
ServerName = cabinet.NotesServer ' get cannonical Name of the server 

'get the referenced document
Set cabinetDB = New Notesdatabase("","")
Call cabinetdb.OpenByReplicaID( ServerName, DBReplicaID )
Set DDGetReferencedDocForDDoc = cabinetdb.GetDocumentByUNID(DocUnID )
End Function

Я подозреваю что проблема либо в сборщике мусора LS, либо в моем разрушенном мозге.
Стоит добавить, что я разбил одну функцию созданную разработчиками на 2, в общем то изменения не страшные просто вынес часть функционала в другую функцию, это было необходимо для более удобного использования
 
S

SkinGreek

значит дело в моем разрушенном мозгу:rolleyes:(((
Ну почему все так плохо, хотя конечно оправдано убийство документа при разрушении ссылки на БД.
единственное подходящее решение вижу в создании класса с подобными функциями.

Akupaka
Спасибо огромное, мне б такую внимательность как у вас))
 
A

Akupaka

сделай в тех функциях, если есть желание, кеширование объектов БД, например:

Код:
Globals
dim dbCache list as notesDatabase

Function DDGetReferencedDocForDDoc(DDoc As Variant) As Notesdocument

...


if not(cabinetDB is nothing) then
set dbCache(cabinetDB.Server & "!!" & cabinetDB.FilePath) = cabinetDB
end if


'get the referenced document
Set cabinetDB = New Notesdatabase("","")
Call cabinetdb.OpenByReplicaID( ServerName, DBReplicaID )
Set DDGetReferencedDocForDDoc = cabinetdb.GetDocumentByUNID(DocUnID )
End Function

еще через объект gWFSession можно кешить объекты, но я не помню какой синтаксис...
 
S

SkinGreek

ага получилось, немного с другой логикой но всеж
Спасиб за идею. А то пришлось бы копипастить чтоб уже имеющийся интерфейс не ломать.
Сделал вот так
Код:
	If Iselement(dbCache(ServerName & "!!" & DBReplicaID)) Then
Set cabinetDB = dbCache(ServerName & "!!" & DBReplicaID)
Else
Set cabinetDB = New Notesdatabase("","")
Call cabinetdb.OpenByReplicaID( ServerName, DBReplicaID )
Set dbCache(ServerName & "!!" & DBReplicaID) = cabinetDB
End If
Единственное подложечкой сосет тот факт что dbCache глобальна на уровне библиотеки. То есть зависит от времени жизни библиотеки. Если б был класс то его временью жизни было бы по-гибче управлять. Библиотека умирает после отработки агента так?
 
A

Akupaka

в общем, да, когда заканчивается выполнение использующего кода...

ну, экземпляр класса дольше не проживет... а содержимое глобальной переменной можно убить, см. erase
 
S

SkinGreek

я наобород чем меньше она будет жить тем лучшее, то есть инстанцию класса создал внутри функции и она умрет по окончании работы функции, а если надо чтоб кеш жил на уровне агента/формы и тд то в его декларациях и объявлять переменную данного класса.

Ну в общем то предложенный вами вариант вполне подходит так как интерфейс библиотеки менять нельзя, а копипастить в свой класс-утилиту тоже не красиво.

Да и время жизни вполне приемлемо.
В общем решение самый раз. еще раз спасибо!:)
 
A

Akupaka

а если надо чтоб кеш жил на уровне агента/формы и тд то в его декларациях и объявлять переменную данного класса
ну, вообще-то, агент подгружает инстанс библиотеки в начале выполнения, а в конце - выгружает.
соотв. живет эта переменная лишь для текущего выполнения агента. снова уточню, что убить ее содержимое можно в любой момент оператором erase.
в данном случае класс не представляет преимуществ, кроме удобства, возможно...
еще раз спасибо
да не за что, в общем :)
 
Мы в соцсетях:

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