以地籍库为例介绍AutoCAD数据库连接

李 玲
(广西第一测绘院)

【摘 要】 以地籍库为例,介绍AutoCAD2000的数据库连接功能dbConnect。通过地籍库的建立及维护过程,介绍数据库的连接、图形与数据维护的一致性。
【关键词】 AutoCAD 数据库连接 维护 一致性

  1 引言
  自从AutoCAD R12将AutoCAD SQL Extension(ASE)引入后,AutoCAD用户就有了将AutoCAD对象链接到外部数据库的能力。AutoCAD 2000将其所有的数据库连接功能组合在一起,形成单一的易于理解的用户界面,称之为dbConnect,dbConnect完全取代了AutoCAD早期版本中老的ASE界面。在AutoCAD 2000中,数据库连接的特点是基于微软的OLE DB技术,通过一个组件对象模型(COM)编程界面——ActiveX数据对象(ADO),可以完全控制OLE DB。ADO能够用在支持COM的任何计算机语言中,也包括AutoCAD编程环境,例如 VBA 和 Visual LISP。本文以地籍库为例,以Visual LISP为编程环境,介绍AutoCAD 2000的数据库连接及图形与数据库维护的一致性。
  2 图形与数据库的连接
  在AutoCAD中,用数据库进行任何工作之前,必须先建立到数据库的连接。
  2.1 建立数据库连接
  2.1.1 配置数据源
  设D:\宗地\目录下有Access的Parcel.mdb文件,其中表Table1,表的结构如下:
  Table1:

ID
街道号
街坊号
宗地号
土地利用类别
权属人
宗地面积

  现在要在名为Parcels的图形中连接Parcels.mdb,连接方法可以手工连接,也可以用程序自动连接。手工连接的方法如下:
  1)打开parcels.dwg
  2)从Tools菜单中选择dbConnect。出现dbConnect管理器。
  3)在dbConnect管理器中右击Data Sources,并从捷菜单中选择Configure a Data Source,显示Configure a Data Source对话框。
  4)键入 “parcels”作为数据源名,点击OK。出现Data Link Properties对话框。
  5)在OLE DB Providers列表框中选择Microsoft Jet 3.51 OLE DB Provider,按Next>>。
  6)键入Parcel.mdb文件的完整路径。
  7)点击Test Connection 校验连接是否建立。
  8)点击OK。
  一旦数据源配置完成,在DATA Links目录生成一个UDL文件,它的名字出现在dbConnect管理器窗口中的Data Sources节点下。
  自动创建连接的过程其实就是通过程序创建如上所述的UDL文件的过程,这里不再详述。
  2.1.2 用ADO获取连接到AutoCAD设置的数据源
  用LoadAdo函数获取连接到ACAD设置的数据源,为下面的函数连接数据库作准备。
  (defun LoadAdo( / gADO-DLLpath )
    (vl-load-com) ;装载ActiveX
    (setq acadObj (vlax-get-acad-object)
       acadDoc (vla-get-ActiveDocument acadObj)
    gADO-DLLpath "c:\\program files\\common files\\system\\ado\\msado15.dll")
  (if (null ado-adOpenDynamic)
  (vlax-import-type-library
    :tlb-filename gADO-DLLpath
    :methods-prefix "ado-"
    :properties-prefix "ado-"
    :constants-prefix "ado-"
    ) ;装载ADO Library
  )
  (setq ADOConnect (vlax-create-object "ADODB.Connection")) ;创建全程变量ADOConnect
  (setq wsPath (vlax-get-property
          (vlax-get-property
             (vlax-get-property
                  (vlax-get-acad-object)
             "Preferences"
           )
          "Files"
           )
          "WorkspacePath"
       )
     name ( getvar "dwgname")
     len (strlen name)
     name (substr name 1 (- len 3))
     name (strcat name "udl")
  adoString (strcat "File Name=" wsPath "\\" name ";User ID=;Password=;" )
  ) ;取数据源udl文件路径
  (vlax-put-property ADOConnect "ConnectionString" adoString)
  ; ADOConnect 将 name.mdb 连接到name.udl文件
  (vlax-invoke-method ADOConnect "Open" adoString "" "" -1)
  ); end LoadAdo
  2.2 建立链接模板
  2.2.1 建立链接模板
  链接对象到数据库之前,必须先建立链接模板,建立链接模板的过程如下:
  1)打开上面已连接数据库的Parcels图形。
  2)打开dbConnect管理器并连接到parcels数据源。
  3)右击Table1表,并选择New Link Template。显示New Link Template对话框。
  4)将链接的默认名称Table1_DataLink1改为Parcels(与图形名相同)。点击Continue进入Link Template对话框,点击ID旁边的框指定ID为关键列,然后点击OK。现在dbConnect管理器中会看到在图形parcels下面的Parcels节点。
  2.2.2 用CAO获取链接模板
  (defun LoadCao( / linkTemplates name linkname MDBname len index)
   (if (null caom-GetLinkTemplates) ;检查CAO library 是否装载
   (progn
    (vlax-import-type-library
     :tlb-filename "cao15.dll"
     :methods-prefix "caom-"
     :properties-prefix "caop-"
     :constants-prefix "caok-"
    ) ;装载CAO Liabrary
  ))
  (setq CAOConnect (vlax-create-object "CAO.DbConnect"))
  (setq linkTemplates (vl-catch-all-apply 'caom-GetLinkTemplates
            (list CAOConnect acadDoc))
  )
   (setq name (getvar "dwgname")
      len (strlen name)
      name (substr name 1 (- len 4))
      index 0
      count (vlax-get-property linkTemplates "Count")
     MDBname ""
     linkTemplate nil
    )
  (while (< index count)
  (setq linkTemplate (vlax-invoke-method linkTemplates "Item" index)
      linkname (vlax-get-property linkTemplate "Name")
      MDBname (vlax-get-propertylinkTemplate "DataSource")
      index (1+ index)
  )
     (if (= name MDBname)
      (setq index count)
     )
  );在图形链接模板库中搜寻Parcels链接模板
   (if (/= name MDBname)
     (setq linkTemplate nil)
   )
  linkTemplate ;使函数返回Table1的链接模板
  )
  2.3 宗地与数据库的自动链接
  在parcels图形中画一权属界线,并将其链接到数据库(以界线对应的图形句柄作为数据库中表Table1的ID号,因为AutoCAD中图形句柄是唯一的):
  (defun draw (/)
   (setq p (getpoint “\n权属界线第一点:”))
   (while p
    (setq plist (append plist (list p)))
    (setq p (getpoint “\n下一点:”))
  )
  (if plist
  (progn
   (setq ename (LandPline plist));函数LandPline根据节点列表画出权属界线,并返回对应的实体名
   (append_DB ename) ;在数据库中加入权属界线对应的数据记录
   (MakeLink ename) ;将权属界线链接到数据库中对应的数据记录
  ))
  );end defun draw

  其中,append_DB及MakeLink函数定义如下:
  (defun append_DB (ename / Object ID area m_plist RS fields fields Count Index
             thisField value)
   (setq Object (vlax-ename->vla-object ename))
         ID (vla-get-Handle Object) ;取实体的句柄
        area (vla-get-area Object) ;取实体面积
  )
  (setq m_plist (list ID "" "" "" "" "" (rtos area 2 6)));预定义数据记录各字段的数值
  (cond
    ; Create the ADO Recordset object
    ((null (setq RS (vlax-create-object "ADODB.Recordset")))
    (princ "\nUnable to create ADODB.Recordset object.")
  )
    ((null (ok 'ado-Open (list RS "Table1" ADOConnect ado-adOpenDynamic
            ado-adLockOptimistic ado-adOptionUnspecified)));其中ADOConnect为函数LoadADO中返回的数据库连接
  )
  (T
    (ado-AddNew RS) ;在Table1中追加一空白记录
    (setq fields (ado-get-Fields RS)
       fieldsCount (vlax-get-property fields "Count")
          index 0
  )
    (while (< index fieldsCount)
    (setq thisField (vlax-get-property fields "item" index)
         value (nth index m_plist)
         index (1+ index)
    )
    (ado-put-Value thisField value ) ;将预定义的数值赋予各字段
   ) ;将空白记录各字段赋值
   (ado-Update RS) ;向数据库提交变化
  )
  );end cond
    (ReleaseRS RS)
  );End Defun append_DB
   (defun ReleaseRS (RS)
    (if RS
    (progn
     (if (= (ado-get-State RS) ado-adStateOpen)
      (ado-Close RS)
     )
     (vlax-release-object RS)
     (setq RS nil)
    ))
  )
  以上的append_DB在数据库记录中加入ID和宗地面积,使宗地图形与数据库记录一一对应,宗地的其他属性可以在数据库中手工录入。
  (defun MakeLink( ename / VlaObj objectID vlax-obj currKeyValues OneKeyValue linkResult)
    (setq linkTemplate (LoadCao))
    (setq VlaObj (vlax-ename->vla-object ename)
    objectID (vla-get-Handle VlaObj)
    vlax-obj (vlax-get-property VlaObj "ObjectID")
   currKeyValues (vlax-create-object "CAO.keyValues")
    OneKeyValue (vlax-create-object "CAO.KeyValue")
  )
  (vlax-put-property OneKeyValue "FieldName" "ID")
  (vlax-put-property OneKeyValue "Value" objectID)
  (vlax-invoke-method currKeyValues "Add" OneKeyValue)
  (setq linkResult (vl-catch-all-apply 'caom-CreateLink (list linkTemplate lax-obj currKeyValues) ))
   (if (vl-catch-all-error-p linkResult)
       (princ "\n Trying to execute CreateLink() caused an ActiveX error:")
   )
  );end defun MakeLink
  3 图形与数据的一致性
  宗地的变化包括权属界线的节点的变化(删点、增点、移点)和宗地的分割、合并。节点的变化仅引起图形和数据记录的改变,图形与数据间的链接关系不变;宗地的分割、合并不仅会引起图形的变化、记录的增减,图形与数据间的链接关系也相应发生改变。
  3.1 权属界线节点变化
  以移点为例:
  (defun c:MoveDot ( / ename ss point newpoint oldpoint xylist vlaxobj objID area)
  (setq point (getpoint "\n请选待移动的界址点: [或回车=退出]"))
  (if point
  (progn
   (setq newpoint (getpoint "\n移动到点:"))
   (setq ss (ssget point))
   (setq ename (ssname ss 0))
   (setq xylist (GetPlXY ename) ) ;函数GetPLXY取界线的节点列表
   (setq oldpoint (Plist-DotAt xylist point) ;函数Plist-DotAt返回节点列表中最靠近point的节点
   (Update-ename ename oldpoint newpoint) ;函数Update-ename将界线对象ename中的oldpoint替换成newpoint
   (setq vlaxObj (vlax-ename->vla-object ename)
      objID (vla-get-Handle vlaxObj)
      area (rtos (vla-get-area vlaxObj) 2 6)
   )
  (setq SQLstr (strcat "UPDATE " table " SET 宗地面积='"area "' where ID='" objID "'" )) ;定义SQL语句
    (if (null (ok 'ado-Execute (list db SQLstr nil ado-adOptionUnspecified)));执行SQL语句,将数据记录中的宗地面积更新
  (progn
  (princ "\nUnable to Update record.")
  (exit)
  ))
)
  3.2 宗地分割与合并
  以宗地分割为例,如图1所示:权属界线由点1至点7构成,分割线由点t1至点t3构成,分割线将宗地分割为Z1、Z2宗地。

  (defun c:Split ( / ename iename xylist inplist plist enam1 ename2 vlaxObj ID SQLstr)(setq ename   (car(entsel “\n选取欲分割的权属界线:”))
  (setq iename (car (entsel “\n选取分割线:”)))
  (setq inplist (GetPlXY iename)) ;函数GetPlXY 返回分割线节点列表
  (setq xylist (GetPlXY ename));函数GetPlXY 返回权属界线节点列表
  (setq plist (SplitPlist xylist inplist));SplitPlist函数返回分割后的两个复合线列表:((点1 点2 i1 t2 i2 点7)   (i1 点3 点4 点5 点6 i2 t2))
  (setq xylist1 (car plist) xylist2 (cadr plist))
  (setq ename1 (LandPline xylist1) ename2 (LandPline xylist2))
  ;LandPline函数根据节点列表构造权属界线,并返回界线对应的实体名
  (setq vlaxObj (vlax-ename->vla-object ename)
      ID (vla-get-Handle vlaxObj)
  )
  (setq SQLstr (strcat "DELETE FROM " table " where ID='" ID "'") )
  (if (null (ok 'ado-Execute (list ADOConnect SQLstr nil
                 ado-adOptionUnspecified)))
   (progn
    (princ "\nUnable to delete record.")
    (exit)
   )
  )
  ;执行SQL语句,将原权属界线对应的数据记录删除,相应的链接关系也被删除
  (command "erase" ename "") ;将原权属界线删除
  (append_DB ename1) ;在数据库中建立宗地Z1对应的数据记录
  (Make_Link ename1) ;将宗地Z1的权属界线链接到对应的数据记录
  (Append_DB ename2) ;在数据库中建立宗地Z2对应的数据记录
  (Make_Link ename1) ;将宗地Z2的权属界线链接到对应的数据记录
  );End Defun Split
  4 结束语
  本文以地籍库的建立及维护过程为例,较详细的介绍了AutoCAD2000的数据库连接dbConnect功能。出于篇幅考虑,文中与dbConnect无紧密联系的函数略去不表。希望本文能对读者取到参考作用。

参考文献:
[1] (美)Scott McFarlane著;罗阿理等译.AutoCAD数据库连接.机械工业出版社,2001.5
[2] 郭剑蜂,陈杉,王宁编著.用Visual LISP开发AutoCAD 2000应用程序. 人民邮电出版社,2000.1
[3] 汤峻编.AutoCAD2000高级应用与Visual LISP 开发宝典. 人民邮电出版社,2001.1

地址:广西南宁市建政路5号  邮编:530023  Tel:0771-5606397  Email:webmaster@digitalgx.com
广西基础地理信息中心版权所有 2005-2010 广西基础地理信息中心制作