第 章 数据库基础: 创建我们自己的Employee 对象
打开Lab文件夹下的Lab工程文件或或接着Lab的代码
在这一章中我们将创建一个Employee 对象(包括一个圆一个椭圆和一个多行文本对象)这个对象属于一个自定义的EmployeeBlock块(这个块驻留在EmployeeLayer层当在模型空间插入这个块的时候EmployeeLayer层就会拥有这个块的一个块索引)本章的每一个步骤中的代码都可以运行这样做的目的可以使你更清楚地知道每一部分代码完成的功能第一步将简要说明一下如何在模型空间创建一个圆
这一章的重点是在AutoCAD中访问数据库的基础主要内容包括事务处理(Transaction)对象Id(ObjectId)符号表(symbol tables如块表BlockTable和层表LayerTable)以及对象引用使用的其它一些对象如颜色Color三维点Pointd和三维向量Vectord都和各自的步骤有关但重点应该放在数据库基础上
) 创建一个名为CREATE的命令它调用函数CreateEmployee()这个函数用来在模型空间(MODELSPACE)的()点处创建一个半径为的圆
[CommandMethod(test)]
public void createCircle()
{
//首先声明我们要使用的对象
Circle circle; //这个是我们要加入到模型空间的圆
BlockTableRecord btr;//要加入圆我们必须打开模型空间
BlockTable bt; //要打开模型空间我们必须通过块表(BlockTable)来访问它
//我们使用一个名为Transaction的对象把函数中有关数据库的操作封装起来
Transaction trans;
//使用TransactionManager的StartTransaction()成员来开始事务处理
trans = HostApplicationServicesWorkingDatabaseTransactionManagerStartTransaction();
//现在创建圆……请仔细看这些参数——注意创建Pointd对象的New和Vectord的静态成员ZAxis
circle = new Circle(new Pointd( ) VectordZAxis );
bt = (BlockTable)transGetObject(HostApplicationServicesWorkingDatabaseBlockTableId OpenModeForRead);
//使用当前的空间Id来获取块表记录——注意我们是打开它用来写入
btr = (BlockTableRecord)transGetObject(HostApplicationServicesWorkingDatabaseCurrentSpaceIdOpenModeForWrite );
//现在使用btr对象来加入圆
btrAppendEntity(circle);
transAddNewlyCreatedDBObject(circle true); //并确定事务处理知道要加入圆!
//一旦完成以上操作我们就提交事务处理这样以上所做的改变就被保存了……
transCommit();
//…然后销毁事务处理因为我们已经完成了相关的操作(事务处理不是数据库驻留对象可以销毁)
transDispose();
}
请仔细阅读一下上面的代码块的结构可以通过注释来了解相关的细节
注意要编译代码你必须导入AutodeskAutoCADDatabaseServices 和AutodeskAutoCADGeometry命名空间
运行这个函数来看看它是否可行应该会在图形中创建一个在()处的半径为的白色的圆
) 我们可以减少代码的输入量这可以通过声明一个Database变量代替HostApplicationServicesWorkingDatabase来实现
Database db = HostApplicationServicesWorkingDatabase;
使用这个变量来代替在代码中出现的HostApplicationServicesWorkingDatabase
) 在上面的代码中我们没有使用任何异常处理而异常处理对一个正确的NET应用程序来说是非常重要的我们要养成使用异常处理的好习惯所以让我们在这个函数中加入trycatchfinally
) 为了使代码紧凑我们可以把许多变量的声明和初始化放在同一个语句中现在你的代码看起来应该是这样的
[CommandMethod(CREATE)]
public void CREATEEMPLOYEE()
{
Database db = HostApplicationServicesWorkingDatabase;
Transaction trans = dbTransactionManagerStartTransaction();
try
{
Circle circle = new Circle(new Pointd( ) VectordZAxis );
BlockTable bt = (BlockTable)transGetObject(dbBlockTableId OpenModeForRead);
BlockTableRecord btr = (BlockTableRecord)transGetObject(HostApplicationServicesWorkingDatabaseCurrentSpaceIdOpenModeForWrite);
btrAppendEntity(circle);
transAddNewlyCreatedDBObject(circle true);
transCommit();
}
catch
{
edWriteMessage(Error );
}
finally
{
transDispose();
}
}
End Function
运行你的代码来进行测试……
上面的catch块只显示一个错误信息实际的清理工作是在finally块中进行的这样做的理由是如果在事务处理被提交(Commit())之前Dispose()被调用的话事务处理会被 销毁我们认为如果在transCommit()之前出现任何错误的话你应该销毁事务处理(因为Commit将永远不会被调用)如果在Dispose()之前调用了Commit()也就是说没有任何错误发生那么事务处理将会被提交给数据库
所以基于上面的分析Catch块其实并不是必须的因为它只用来通知用户程序出现了一个错误它将在下面的代码中被去掉
) 现在让我们在Employee加入剩下的部分椭圆和多行文本的实例
多行文本实体
中心点应该与圆心的创建一样
(建议创建一个名为center而值为的Pointd变量来表示中心点)
多行文本的内容可以是你的名字
椭圆(提示你可以先看一下Ellipse的构造函数)
法向量应该沿着Z轴(请查看Vectord类型)
主轴设为Vectord()(提示不要忘了用new)
半径比例设为
椭圆还必须闭合(也就是说开始和结束点必须相同)
运行你的代码来进行测试……应该可以生成一个圆一个椭圆和一个中心点在的多行文本
注意和事务处理对象有关的NET API中的TryCatchFinally块结构应该是异常观察者实际上我们是在try块中实例化对象的但没有显式地销毁它们当产生异常的时候可能会产生问题特别是当观察者注意到我们实际上用的是封装的非托管对象!记住当资源不再使用的时候垃圾收集机制就会回收内存垃圾收集机制会不时的调用封装类的Dispose()方法删除非托管对象
这里还要注意的是Dispose()作用于封装的非托管类对象的方式取决于对象是否是数据库驻留对象由非数据库驻留对象调用的Dispose()会删除非托管对象而由数据库驻留对象调用的Dispose()只是关闭它们
<![if !supportLineBreakNewLine]>
<![endif]>
) 接下来让我们来创建一个新的函数它用来新建一个颜色为黄色名字为EmployeeLayer 的AutoCAD层
这个函数应该检查是否这个层已经存在但不管这个层是否存在函数都应该返回EmployeeLayer的ObjectId下面是这个函数的代码
public ObjectId CreateLayer()
{
ObjectId layerId; //它返回函数的值
Database db = HostApplicationServicesWorkingDatabase;
Transaction trans = dbTransactionManagerStartTransaction();
//首先取得层表……
LayerTable lt = (LayerTable)transGetObject(dbLayerTableId OpenModeForWrite);
//检查EmployeeLayer层是否存在……
if (ltHas(EmployeeLayer))
{
layerId = lt[EmployeeLayer];
}
else
{
//如果EmployeeLayer层不存在就创建它
LayerTableRecord ltr = new LayerTableRecord();
ltrName = EmployeeLayer; //设置层的名字
ltrColor = ColorFromColorIndex(ColorMethodByAci );
layerId = ltAdd(ltr);
transAddNewlyCreatedDBObject(ltr true);
}
transCommit();
transDispose();
return layerId;
}
是不是觉得这个函数的基本结构与在模型空间加入实体的代码比较类似?访问数据库的方法都是这样的使用事务处理来获取数据库对象在符号表(模型空间所在的块表也是符号表之一)中加入实体然后让事务处理知道
) 在这个函数中加入异常处理就像在CreateEmployee函数中的一样
) 接下来改变新建层的颜色下面是实现的代码片断请把它加入到你的代码中
ltrColor = ColorFromColorIndex(ColorMethodByAci )
注意ColorMethodByAci可以让我们使用AutoCAD ACI颜色索引……这里为(表示黄色)
<![if !supportLists]>) <![endif]>回到CreateEmployee()函数加入把上面创建的几个实体设置到EmployeeLayer层的代码声明一个类型为ObjectId的变量用CreateLayer函数的返回值给它赋值使用每个实体(文本圆和椭圆)的LayerId属性设置它们所在的层
例如 textLayerId = empId
运行代码来查看EmployeeLayer层是否已被创建所有已创建的实体是否都在这一层上(应该显示为黄色)
) 现在为各个实体设置不同的颜色可以使用ColorIndex属性(ColorIndex属性表示AutoCAD的颜色)
圆为红色-
椭圆为绿色-
文本为黄色-
运行代码看看实体的颜色是否为设置的值即使这些实体是在EmployeeLayer层上
) 接下来我们要在AutoCAD数据库中创建一个独立的块然后把它插入到块表而不是模型空间中
首先把CreateEmployee函数的名字改为CreateEmployeeDefinition()
加入以下代码来创建一个独立的块
BlockTableRecord newBtr = new BlockTableRecord();
newBtrName = EmployeeBlock;
newBtrId = btAdd(newBtr);
transAddNewlyCreatedDBObject(newBtr true);
) 现在请稍微改动一下加入实体到模型空间的代码(改为加入块到块表中记得加入前要打开块表)
现在运行代码然后使用INSERT命令来检查是否可以正确插入这个块
) 最后我们要创建一个位于模型空间的块索引它表示上面创建的块的一个实例这一步留给大家练习
下面是你要遵循的最基本的步骤
<![if !supportLists]>A) <![endif]>创建一个名为CreateEmployee新的函数
<![if !supportLists]>B) <![endif]>把命令属性CREATE移动到CreateEmployee()
<![if !supportLists]>C) <![endif]>修改CreateEmployeeDefintion()来返回新创建的块EmployeeBlock的ObjectId操作的步骤请参考CreateLayer()的作法
<![if !supportLists]>D) <![endif]>你需要修改CreateEmployeeDefintion()来查看块表中是否已包含EmployeeBlock块如果包含这个块则返回它的ObjectId(做法与CreateLayer()一样)
提示把bt的声明语句移动到try块的顶部使用BlockTableHas()方法把其它的代码移动到else语句
try
{
//获取BlockTable 对象
BlockTable bt = (BlockTable)transGetObject(dbBlockTableId OpenModeForWrite);
if ((btHas(EmployeeBlock)))
{
newBtrId =bt[EmployeeBlock];
}
else
{
…
<![if !supportLists]>E) <![endif]>在新创建的CreateEmployee()函数中创建一个新的BlockReference对象并把它加入到模型空间提示我们可以使用CreateEmployeeDefinition()中引用模型空间的代码这些代码在这里不需要了
<![if !supportLists]>F) <![endif]>在CreateEmployee中调用CreateEmployeeDefinition()函数使上面生成的BlockReference对象的BlockTableRecord()指向CreateEmployeeDefinition()函数提示请参考BlockReference的构造函数