Lotus与ODBC交互.docx
《Lotus与ODBC交互.docx》由会员分享,可在线阅读,更多相关《Lotus与ODBC交互.docx(17页珍藏版)》请在冰豆网上搜索。
Lotus与ODBC交互
LotusDominoR5开发心得
----LotusDomino是当今办公自动化系统的主流开发平台之一,目前大部分企业和机构都在使用LotusDomino开发自己的无纸办公系统。
不久前,我参加的一个OA系统开发项目就是使用LotusDominoR5开发的。
在开发过程中,我积累了一些小技巧,现在公布出来,希望能给相关人士提供一些帮助。
----一.LotusDomino与关系数据库的互操作
----在项目开发过程中,遇到的第一个棘手的问题是:
如何把原先的关系型数据库中的内容全部导入Domino中?
因为企业现在的所有数据都集中在一个关系型数据库中,因此希望Notes库能与旧的关系库互操作,而不必在数据库转换上浪费更多人力。
----此外,由于LotusNotes是非结构化的数据库,而关系数据库属于结构化数据库,因此要实现两者的互操作或数据导入/导出势必需要一个专门的转换程序,而这个程序一般来说都属于附加品,要么由Lotus提供,要么由数据库厂商提供,如LotusNotes与Oracle数据库之间的转换就有专门的程序(Pump)。
一般在购买Lotus产品的时候Lotus公司不会提供此类产品,如果需要可以单独购买。
而对于企业来说,如果企业数据存放在不止一个关系库中,那么就需要购买若干个此类产品,而且还不一定能买的到,因此能否通过LotusScript编写一个通用的数据库转换程序就成为本次开发的难点之一。
----解决这个问题用到了LotusDominoR5中提供的三个LotusNotes对象类:
ODBCConnection(ODBC连接)、ODBCQuery(ODBC查询)以及ODBCResultSet(ODBC结果集)。
应用这三个类并辅以LotusScript语言就能实现与关系数据库的互操作问题。
----具体解决方法如下:
----第一步在控制面板——>32位ODBC数据源中建立用户数据源Test;
----第二步在DominoR5中新建一个数据库Try,并建立一个空白表单Connection,此表单没有任何内容,然后在表单上创建一个“操作”,起名为“Read”;
----第三步在“Read”操作的编程窗口中选择编程语言为LotusScript;
----第四步在编程窗口的对象窗口中点击“Option”事件,并写入如下脚本:
----Uselsx"*lsxodbc"//使用LotusScript扩展对象中的ODBC类
----第五步选中“Declare”事件,在其中写入:
DimsessionAsNotesSession
DimdbAsNotesDataBase
DimdocAsNotesDocument
DimqryAsODBCQuery
DimresultAsODBCResultSet
DimconAsODBCConnection
定义程序中使用到的各种对象。
第六步选中“Click”事件,在其中写入:
SubClick(SourceAsButton)
'SetNewValue
Setsession=NewNotesSession
Setcon=NewODBCConnection
//新建ODBCConnection对象实例
Setqry=NewODBCQuery
//新建ODBCQuery对象实例
Setresult=NewODBCResultSet
//新建ODBCResultSet对象实例
'取得当前数据库信息
Setdb=session.CurrentDataBase
Setdoc=NewNotesDocument(db)
//新建文档
doc.form="connection"
//新建文档的表单指向connection
Callcon.Disconnect()
//保证con对象当前没有连接其他数据源
Ifcon.ConnectTo("test")Then
//如果连接成功
Setqry.connection=con
//将建立好连接的con交给query对象
qry.SQL="SELECT*FROMTable1"
//SQL语句
Setresult.Query=qry
//将已经连接上数据源并写好SQL
语句的query对象赋给result对象
Callresult.Execute()//执行SQL语句
Do//循环直到结果集为空
Callresult.NextRow()//指针指向下一条记录
Fori=1Toresult.Numcolumns
//Numcolumns属性记录关系库中的字段个数
field=result.FieldName(i)
//根据字段的索引值得到字段的名字
value=result.GetValue(field)
//取得字段值
IfIsdate(value)Then
//对日期字段的特殊处理
Ifvalue=Datevalue("0:
00:
00")Then
value=""
Else
value=Format(value,"mm-dd-yyyy")
EndIf
EndIf
Setitem=doc.AppendItemValue(field,value)
//将关系库中的值写到Notes当前库的当前表单中
Next
Calldoc.save(True,True)
//当一条记录的所有字段都被写入
Notes库后保存此文档
Setdb=session.CurrentDataBase
Setdoc=NewNotesDocument(db)//新建文档
doc.form="connection"
LoopUntilresult.IsEndOfData
Callcon.Disconnect()//断开与数据源的连接
Else
Messagebox("Couldnotconnecttoserver")
EndIf
EndSub
----最后,保存表单并运行,用鼠标点击Read操作后,关系数据库中的内容就被取到Notes的文档型数据库中了。
----下面简要说明一下上述代码:
*****关系数据库的字段要于lotus库的名称域对应
----1.New。
New关键字是用来创建Notes对象的。
New后面是要创建的Notes对象及所需的参数。
使用New关键字需要注意的一点是:
在Declare事件中声明Notes对象的时候不能使用New关键字,否则编译时会出错;但是在Click事件中可以按DimdbAsNewNotesDatabase(“”,“***.NSF”)格式书写。
----2.ODBCConnection对象是与ODBC建立连接的Notes对象,使用它的ConnectTo方法可以与ODBC用户数据源中定义的任何一个数据源建立连接,同时返回一些相关的信息,如:
表的个数,表中的字段数等。
----3.ODBCQuery对象是用户编写标准的SQL查询语句的对象,它的connection属性是指向已经与ODBC数据源建立好连接的ODBCConnection对象的;它的SQL属性是存放用户编写的SQL语句。
----4.ODBCResultSet对象是执行SQL查询语句之后存放查询结果的,它的Query属性是指向包含建立起连接(ODBCConnection)的并写好SQL语句的ODBCQuery对象。
----5.ODBCResultSet对象的NextRow方法的作用是将ODBCResultSet的记录指针指向下一条记录。
因为在取到关系数据库中的记录之后,ODBCResultSet对象的指针是为空的,也就是说它并不自动指向结果集的第一条记录,NextRow方法即实现了将记录指针指向第一条记录的功能,并且在以后的循环过程中,此方法还将继续把指针逐一指向后面的记录,直到最后一条。
----6.由于原先的关系数据库中的字段比较多,所以采用在程序中直接写入字段名的做法并不明智,因此,本程序使用了ODBCResultSet对象的FieldName(fieldindex)方法来通过字段的编号获得字段名,然后再使用GetValue(fieldname)函数得到域值,最后调用Document类的AppendItemValue(fieldname,value)函数在表单中追加一个名为fieldname的域并赋值。
----在把上述三个对象的属性分别设置好以后,调用ODBCResultSet对象的Execute方法,就可以从关系库中读取数据了。
----但是使用上面的代码在进行实际数据库内容转换的时候,发现Notes通过ODBC数据源连接关系数据库时,无法识别中文字段名。
如果关系数据库的字段是中文名字,那么ODBCResultSet将为空,解决的办法是将关系数据库中的所有字段都改为英文名字。
经过反复测试,发现并不是所有的中文字段名Notes都不识别,是同关系库的驱动程序有关,由于本次开发连接的是Foxpro的DBF数据库,使用的是Foxpro2.6数据库驱动,因此无法通过ODBC获取中文字段名,如果连接的关系库是MicrosoftSQLServer7.0则可以通过ODBC数据源识别中文字段名。
----在实际数据库的转换过程中同时发现的问题还有:
该程序执行完一次后不能把关系型数据库中的内容全部取出来。
由于需要转换的关系型数据库的结构比较复杂,共有40多个字段,且包括字符、字符串、日期、数字等多种数据类型,同时库中的记录比较多(共有3000多条记录),因此出现这个问题后,有两个猜测,一是和ODBC驱动所设置的系统缓冲有关,一是和Notes开辟的内存空间有关,然而通过试验,最终认为和Notes有关的可能性最大。
这是因为首先,Notes对其所有的类都设置了缓存,这其中也包括ODBCResultSet,通过调试LotusScript脚本并多次单步跟踪脚本的执行情况,发现每次只要执行到同一条数据库记录(例如第3328条记录)时,ODBCResultSet就认为数据集已经到头了,下面的记录就都丢了。
于是使用关系数据库软件打开数据库,并将其中的字段减少若干条后,就可以一次读取出全部3000多条记录。
至于需要减少多少个字段才能一次读取出全部记录跟原先的关系型数据库的结构有关,需要具体情况具体实验,没有定论。
但是可以肯定的一条是Notes本身确实为每个对象类都设置了缓存;并且Notes能根据当前内存的使用情况改变缓存的大小。
其次,当用户开机后不是马上运行LotusNotes而是先运行一个其他的程序,然后再运行Notes时,上面提到的第3328条数据库记录就有所改变,可能变为第3112条记录,也可能变为第3218条记录,这个数字将变得不唯一,具体是多少不得而知,而是与所运行的应用程序有关。
----上述代码实现了通过ODBC数据源读取关系数据库中的内容写到LotusNotes库,同样也可以使用上述方法实现在LotusNotes程序通过ODBC数据源写回到关系数据库的功能,具体实现方法与上面的过程大同小异,因此只在此附上源代码:
(1)Option事件中:
Uselsx"*lsxodbc"
(2)Clicked事件中:
SubClick(SourceAsButton)
DimsessionAsNotesSession
DimdbAsNotesDataBase
DimdcAsNotesDocumentCollection
定义程序中用到的对象类
Setsession=NewNotesSession
Setdb=session.CurrentDataBase
取到当前数据库的信息
DimconAsNewODBCConnection
DimqryAsODBCQuery
DimresultAsODBCResultSet
定义ODBC对象类
Setqry=NewODBCQuery
Setresult=NewODBCResultSet
Ifcon.ConnectTo("test")Then
Setqry.Connection=con
Setresult.Query=qry
qry.SQL="SELECT*FROMtable1"
Callresult.Execute()
Setdc=db.AllDocuments
//得到当前数据库中所有文档的文档集
Ifdc.Count=0Then
//如果文档集为空,则直接退出
result.Close(DB_CLOSE)
con.Disconnect
ExitSub
EndIf
Fori=1Todc.Count//循环,
直到所有文档都被写入关系库
Setdoc=dc.GetNthDocument(i)
//获得第i条文档
Callresult.AddRow()
//在关系库中增加一条记录
ForalljIndoc.Items
Dimstr_nameAsString
DimvalueAsVariant
str_name=j.name
If(str_name<>"FORM")
And(str_name<>"$UpdatedBy")Then
//Notes为每个文档都增加了两个特殊的
NotesItem对象用于标识系统信息
value=doc.GetItemValue(str_name)
Callresult.SetValue(str_name,value(0))
//为关系库中的字段赋值
EndIf EndForall
result.UpdateRow//更新关系库
Next
result.Close(DB_CLOSE)
con.Disconnect
Else
Messagebox("Couldnotconnectserver")
EndIf
EndSub
----二.LotusDomino中的日期处理
----在使用ODBC族对象类与关系数据库进行交互的代码里,有下面一段:
IfIsdate(value)Then
Ifvalue=Datevalue("0:
00:
00")Then
value=""
Else
value=Format(value,"mm-dd-yyyy")
EndIf
Setitem=doc.AppendItemValue(field,value)
Endif
----这一段代码的作用是:
判断从关系库中读取出来的字段是否为日期型字段,如果是,那么判断此日期型字段的值,看它是否为空,如果为空则在写入Notes库的时候做处理,保证写入的是空日期类型,如果此字段的值不为空则直接写入Notes库;如果此字段不是日期型字段,则不做任何处理。
也许有人会问:
为什么对于日期型字段要单独做此番处理?
----答案是:
如果不做上述处理,那么通过ODBCResultSet类取出的日期型字段的值如果为空,则写入Notes库的时候会出现一个特殊日期:
“1899年12月30日”。
为什么会出现这个日期,目前尚不得而知。
但是在LotusScript中由于没有单独的Date数据类型,所以Notes的日期变量是以8个字节的浮点数的形式存在的,其整数部分表示公元某年某月某日,其小数部分表示小时分秒,从午夜开始计数。
----其日期类型可以表示的范围从公元100年1月1日(-657434),到9999年12月31日(2958465)这一天,然后Notes会把9999年12月31日对应的整数日期以及所有超过上述日期范围的日期都换算成1899年12月30日。
Notes为什么会用这种方法处理日期型变量,以及为什么把1899年12月30日作为无法换算日期的默认值这一点目前还没有比较好的解释,但是作为一个数据库转换程序,应该保证转换前后的两个数据库中内容的一致性,因此由于Notes本身没有解决这个问题那么就只能由程序来解决。
解决的思想是:
如果取出来的日期型变量的值为空,那么就应该向Notes库中写入空日期,于是就有了上面的代码。
----在代码中,使用到了一个DateValue(string)函数,此函数的功能是将字符串参数转换成日期数据类型,如果字符串所表示的内容找不到合法的日期数据与之对应,那么此函数将保留字符串的值不变,而仅仅把其数据类型转换成日期型,即实现了强制类型转换函数的功能。
而代码中的“0:
00:
00”字符串是个特殊字符串,在通过ODBC数据源读取关系数据库的记录时,如果关系库中的日期型字段值为空,那么取出的值就是“0:
00:
00”形式的日期(这也许与Microsot公司的ODBC驱动及相关程序有关,因为不只是Notes取出空日期为此值,其他软件甚至包括微软自己的MSQuery组件通过ODBC读取同一关系数据库中的日期型变量时也会出现同样的问题)。
使用DateValue(“0:
00:
00”)语句就可以判断取出的日期型变量的值是否为空,如果为空则将变量Value的值赋成空字符串,然后再写入Notes库中,则可避免出现1899年12月30日这个特殊日期。
----虽然LotusScript中没有提供专门的日期数据类型,但是Lotus却提供了NotesDateTime对象类,其中包括了日期数据的相关处理,如果开发者必须要在程序中处理日期数据而又觉得LotusScript提供的函数不够的话,可以考虑使用NotesDateTime对象。
----三.Notes中视图与表单的关联
----在开发过程中,由于一次错误意外地发现了Notes中视图与表单的关联技巧。
Notes为每个表单都设置了名称与别名两个属性,这两个名字都能标识表单。
在开发过程中,所开发的库有两个表单,分别命名为Form1和Form2,其各自的别名由于疏忽都设成了Document,而每个表单都有一个视图与之对应,在设计Form2的视图时,虽然指定视图中的列都与Form2中的域相关联,但是在运行的时候从视图中双击某条文档欲对其进行编辑时,切换到的表单却是Form1的,多方查找均不能解决这个问题,于是报着试试看的心理改变了表单的别名,分别为Document1和Document2,问题解决。
但是又从出现Form1的视图无法切换到表单的情况,于是又将Form1的别名改回Document,两个视图均能正确切换到自己的表单上。
----由此发现,Notes在建立视图与表单的关联的时候,首先看表单是否具有别名,如果有,则用别名进行关联,一旦对表单的别名进行了改变就得重新设计视图,如果不想重新做视图就不能改变表单的别名。
当然同时也可以应用这一技巧实现从视图中切换到不同表单的功能。
如果表单没有别名,则使用名字进行关联。
摘要本文基于MicroSoft的开放数据库互连技术,介绍了LotusNotes中激活ODBC的基本方法并给出了一个将关系型数据库信息转换到NOTES数据库的实例。
关键词ODBC、DBMS、@DB、ODBCConnection、ODBCQuery、ODBCResultSet
引言自从1989年12月6日,莲花发展公司(LOTUSDEVELOPMENTCORP.)发表了LotusNotes,一种能极大改进公司内部、与其他公司及客户之间的环球通讯、协同工作和协调一致的软件产品。
由于它有很好的电子邮件系统,领先的全文检索和复制功能,还具有极强的安全措施,可以可*地保证安全性,因而得到广泛的应用。
但它也有自身的弱点,在联机事物处理问题,比如:
数据统计、分析、图表生成等功能上还很弱,这时就需要传统的关系型数据库管理系统来实现。
如何把现有的关系型数据库信息转换到Notes数据库中,以便利用LotusNotes中的许多良好性能共享数据库,是本文要讨论的问题。
ODBC概述ODBC(OPENDATABASECONNECTIVITY开放数据库连接)是微软开放的服务结构(WOSA:
MicroSoftWindowsOpenServiceArchitechtrue)中有关数据库的一个组成部分,它规定“以统一的API存取异构数据库信息”是对SQLACCESSGROUP的CLI标准的一种实现,得到了世界上领先的数据库和应用程序开发商的广泛支持。
通过使用这统一的API建立的应用程序,对数据库的操作不依赖于任何数据库管理系统,不直接与任何DBMS(数据库管理系统)打交道,从而直接实现应用程序对不同DBMS的共享。
采用ODBC技术,应用程序只需关心数据的处理而不必考虑数据的存取,编程人员不必了解具体的DBMS,从而极大地减少了软件开发人员的工作量,缩短了开发周期,提高了效率和软件的可*性。
3ODBC工作原理
ODBC接口以SQL作为标准的查询语言来存取连接到的数据源