本节将介绍如何用FDO API进行数据维护,数据维护相关的主要操作如下:
l 插入(Inserting)
l 更新(Updating)
l 删除(Deleting)
l 事务(Transactions)
l 加锁(Locking)
1.1.1 属性值
在执行插入和更新操作之前,往往需要为插入和更新的要素创建属性值。FDO使用类FdoPropertyValue表示属性值,创建一个属性值需要如下两个参数:
l 属性名称
l 值:值的类型必须和属性类型匹配
值可以分为数据类型值和几何类型值,数据类型值用来描述数据类型属性值,几何类型值用于描述几何属性的值,它们的类图如图9‑3所示。
1.1.1.1 创建数据属性值
FDO支持的数据类型有Boolean、Byte、DateTime、Decimal、Double、Int16、Int32、Int64、Single(单精度浮点数)、String、BLOB(二进制大数据对象)、CLOB(字符大数据对象)。创建一个数据类型的值可以通过如下两种方式之一:
1) 使用FdoDataValue,例如:Fdo
2) 使用FdoDataValue的子类
如下的代码展示了如何创建一个Decimal类型数据值,以及Decimal类型属性值。
FdoPtr<FdoDataValue> sampleDataValue = FdoDataValue::Create(100.0, FdoDataType_Decimal); FdoPtr<FdoPropertyValue> sampleDataPropertyValue = FdoPropertyValue::Create("Area", value); 或 FdoPtr<FdoDataValue> sampleDataValue = FdoDecimalValue::Create(100.0); FdoPtr<FdoPropertyValue> sampleDataPropertyValue = FdoPropertyValue::Create("Area", value); |
图 9‑4 FDO值类型的类图
1.1.1.2 创建几何属性值
几何属性值对象包含着一个用字节数组描述的几何对象。一个几何对象可以是简单的,如,点;也可以是复杂的,如,多边形。在几何对象比较复杂的情况下,会创建多个几何对象并将它们合并到一个几何对象,最后把目标几何对象转化成字节数组从而得到几何类型对象。
创建几何属性值对象的步骤如下:
1) 调用静态的Create()方法来创建FdoGeometryValue类型的几何数据对象。
2) 调用静态的GetInstance()方法创建一个FdoAgfGeometryFactory类型的几何工厂对象,该工厂是用来创建几何类型对象的。
3) 调用相应的Create<geometry>()方法来创建所需的几何对象。
4) 用几何工厂将目标几何对象转换成字节数组。
5) 将自己数组合并到几何属性对象中。
FdoPtr<FdoGeometryValue> sampleGeometryValue = FdoGeometryValue::Create(); // 创建一个用来创建几何对象的几何工厂 FdoPtr<FdoFgfGeometryFactory> sampleGeometryFactory = FdoFgfGeometryFactory::GetInstance(); // 定义多边形的外部边界 FdoInt32 numOrdinates = 10; double ordinates[] = {52.0, 18.0, 66.0, 23.0, 73.0, 9.0, 48.0, 6.0, 52.0, 18.0}; FdoPtr<FdoILinearRing> exteriorRing = sampleGeometryFactory->CreateLinearRing(FdoDimensionality_XY, numOrdinates, ordinates); // 创建多边形 FdoPtr<FdoIPolygon> polygon = sampleGeometryFactory->CreatePolygon(exteriorRing, NULL); // 将多边形转换成字节数组,然后设置几何类型的值 FdoPtr<FdoByteArray> geometryByteArray = sampleGeometryFactory->GetAgf(polygon); sampleGeometryValue->SetGeometry(geometryByteArray); // 将FdoGeometryValue类型的添加到几何属性中 FdoPtr<FdoPropertyValue> sampleGeometryPropertyValue = FdoPropertyValue::Create(L"SampleGeometryProperty", sampleGeometryValue); |
1.1.2 插入操作
现在我们可以创建要素数据对象,也就是要素类的实例,并把他们插入到Data Store中。为了便于理解,我们可以认为一个FDO的类就是关系数据库中的一个表,而类的属性相当于表的列,于是添加属性值就是向表中添加一行了。
插入操作包含以下步骤:
1) 创建FdoIInsert类型的插入命令对象,该对象可被多次插入操作重用。
2) 通过调用SetFeatureClassName(<className>)方法来设置需要插入属性值的要素类。
3) 调用插入命令对象的GetPropertyValues()方法来得到FdoPropertyValueCollection类型的属性值集合。在使用插入命令对象插入属性值之前,必须先把各属性值添加到该属性集合中。
4) 创建FdoDataValue类型的数据值或FdoGeometryValue类型的几何值。创建数据值直接调用静态的Create()方法,传入字符串或整型值即可;创建几何类型值请参考几何属性值。
5) 调用静态Create()方法并传入数据类型或集合类型对象来创建FdoPropertyValue类型的属性值对象。
6) 将属性值对象加入到第三步中得到的属性值集合中。
7) 调用Execute()方法执行插入命令。
在前面的章节我们创建了一个要素模式并给它添加了一个要素类,该要素类有三个属性:一个整型数据属性,一个字符串类型属性以及一个几何属性。而后,我们把该要素模式应用到了Data Store中。有了模式和要素类,我们就可以创建要素类的对象并把他们插入到Data Store中了。
以下示例代码展示了如何插入一个整型、字符串以及一个几何类型属性值。
// 创建插入命令 FdoPtr<FdoIInsert> sampleInsert = (FdoIInsert *) connection->CreateCommand(FdoCommandType_Insert); // 插入操作返回的索引值 FdoInt32 valueCollectionIndex = 0; // 为插入命令指定目标要素类 // 传入一个完整的要素类名,其格式为“<schemaName>:<className>” sampleInsert-> SetFeatureClassName(L"SampleFeatureSchema:SampleFeatureClass"); // 得到属性值集合,新建的属性将插入到该集合中 FdoPtr<FdoPropertyValueCollection> samplePropertyValues = sampleInsert->GetPropertyValues(); // 为主键属性创建一个FdoDataValue类型的值 FdoPtr<FdoDataValue> sampleIdentityDataValue = FdoDataValue::Create(101); // 将FdoDataValue添加到主键属性中 FdoPtr<FdoPropertyValue> sampleIdentityPropertyValue = FdoPropertyValue::Create(L"SampleIdentityDataProperty", sampleIdentityDataValue); // 将主键属性值添加到属性值集合 valueCollectionIndex = samplePropertyValues->Add(sampleIdentityPropertyValue); // 为属性“name”创建一个FdoDataValue类型的值 FdoPtr<FdoDataValue> sampleNameDataValue = FdoDataValue::Create(L"Blue Lake"); // 将FdoDataValue类型的值添加到name属性 FdoPtr<FdoPropertyValue> sampleNamePropertyValue = FdoPropertyValue::Create(L"SampleNameDataProperty", sampleNameDataValue); // 将“name”属性值添加到属性值集合 valueCollectionIndex = samplePropertyValues->Add(sampleNamePropertyValue); // 为几何属性创建一个FdoGeometryValue类型的值 // 该多边形描绘了一个带有一个小岛的湖 // 湖的外边界是用Linear Ring来描述的,湖的外边界也是多边形的外边界 // 岛的边界也是用Linear Ring来描述的,岛的外边界是多边形的内部边界 FdoPtr<FdoGeometryValue> sampleGeometryValue = FdoGeometryValue::Create(); // 创建一个用来创建几何对象的几何工厂 FdoPtr<FdoFgfGeometryFactory> sampleGeometryFactory = FdoFgfGeometryFactory::GetInstance(); // 定义多边形的外部边界,也就是“Blue Lake”的外边界 FdoInt32 numBlueLakeShorelineOrdinates = 10; double blueLakeExteriorRingOrdinates[] = {52.0, 18.0, 66.0, 23.0, 73.0, 9.0, 48.0, 6.0, 52.0, 18.0}; FdoPtr<FdoILinearRing> exteriorRingBlueLake = sampleGeometryFactory->CreateLinearRing(FdoDimensionality_XY, umBlueLakeShorelineOrdinates, blueLakeExteriorRingOrdinates); // 定义“Blue Lake”内部小岛“Goose”的边界 FdoInt32 numGooseIslandShorelineOrdinates = 10; double gooseIslandLinearRingOrdinates[] = {59.0, 18.0, 67.0, 18.0, 67.0, 13.0, 59.0, 13.0, 59.0, 18.0}; FdoPtr<FdoILinearRing> linearRingGooseIsland = sampleGeometryFactory->CreateLinearRing(FdoDimensionality_XY, umGooseIslandShorelineOrdinates, gooseIslandLinearRingOrdinates); // 将“Goose”岛的边界加入到内部边界集合中 FdoPtr<FdoLinearRingCollection> interiorRingsBlueLake = FdoLinearRingCollection::Create(); interiorRingsBlueLake->Add(linearRingGooseIsland); // 创建“Blue Lake”多边形 FdoPtr<FdoIPolygon> blueLake = sampleGeometryFactory->CreatePolygon(exteriorRingBlueLake, interiorRingsBlueLake); // 将“Blue Lake”多边形转换成字节数组,然后设置几何类型的值 FdoPtr<FdoByteArray> geometryByteArray = sampleGeometryFactory->GetAgf(blueLake); sampleGeometryValue->SetGeometry(geometryByteArray); // 将FdoGeometryValue类型的“Blue Lake”添加到几何属性中 FdoPtr<FdoPropertyValue> sampleGeometryPropertyValue = FdoPropertyValue::Create(L"SampleGeometryProperty", sampleGeometryValue); // 将几何属性值添加到属性值集合中 valueCollectionIndex = samplePropertyValues->Add(sampleGeometryPropertyValue); // 执行插入操作,插入命令返回一个FdoIFeatureReader FdoPtr<FdoIFeatureReader sampleFeatureReader = sampleInsert->Execute(); |
1.1.3 更新属性值
插入属性之后也可以对属性进行修改。更新操作指的是找出要素类(相当于“表”)、要素(相当于“行”)以及要修改的属性(相当于“行的某一列”),然后用新的属性值取代旧的属性值。
首先,要创建一个FdoIUpdate命令对象,调用该对象的SetFeatureClassName()方法来查找相应的要素类。
然后,创建一个过滤器来查找需要更新的要素对象,调用命令对象的SetFilter()方法可以设置过滤条件。
前面的示例中,要素类SampleFeatureClass包含了一个名为“SampleIdentityDataProperty”的数据属性,它是一个Int32类型的主键属性,也就是说它的值可以唯一确定一个要素,即一 “行”。我们使用主键属性名来设置过滤器,该关键属性的值为‘101’,所以过滤器应该为“(SampleIdentityDataProperty = 101)”。
最后,创建一个新的属性值,将其添加到更新命令并执行。
以下示例展示了如何更新一个属性值。
// 创建更新命令 FdoPtr<FdoIUpdate> sampleUpdate = (FdoIUpdate *)connection->CreateCommand(FdoCommandType_Update); // 为更新命令指定目标要素类 // 传入一个完整的要素类名,其格式为“<schemaName>:<className>” sampleUpdate-> SetFeatureClassName(L"SampleFeatureSchema:SampleFeatureClass"); // 设置过滤条件来锁定目标集合 sampleUpdate->SetFilter(L"( SampleIdentityDataProperty = 101 )"); // 得到属性集合,用以向更新命令中添加属性 // 这里我们将重用插入操作里用到的samplePropertyValues对象 samplePropertyValues = sampleUpdate->GetPropertyValues(); // 为name属性创建一个FdoDataValue类型的对象 FdoPtr<FdoDataValue> sampleNameDataValue = FdoDataValue::Create(L"Green Lake"); // 设置属性名以及对应的值 sampleNamePropertyValue->SetName(L"SampleNameDataProperty"); sampleNamePropertyValue->SetValue(sampleNameDataValue); // 添加name属性对象到更新命令的属性集合中 samplePropertyValues->Add(sampleNamePropertyValue); // 执行命令,返回值为更新命令所更新的要素总数 FdoInt32 numUpdated = sampleUpdate->Execute(); |
1.1.4 删除要素
除了插入和更新操作,我们还可以执行删除操作。删除操作是针对要素的,也就是相当于删除数据库表中的某一行。
首先,需要创建一个FdoIDelete命令对象,调用对象的SetFeatureClassName()方法来找到相应的要素类。然后,创建一个过滤器来定位所要删除的要素,此处的过滤和前面讲到的完全一样。最后,执行删除命令。
以下示例展示了如何删除一个要素。
// 创建删除命令 FdoPtr<FdoIDelete> sampleDelete = (FdoIDelete *)connection->CreateCommand(FdoCommandType_Delete); // 为删除命令指定目标要素类 // 传入一个完整的要素类名,其格式为“<schemaName>:<className>” sampleDelete->SetFeatureClassName(L"SampleFeatureSchema:SampleFeatureClass"); // 设置过滤条件来锁定目标集合 sampleDelete->SetFilter(L"( SampleIdentityDataProperty = 101 )"); // 执行命令,返回值为删除命令所删除的要素总数 FdoInt32 numDeleted = sampleDelete->Execute(); |
1.1.5 管理事务
在9.1.2.2中,我们介绍过事务的概念。一个事务是指由一系列数据操作组成的一个完整的逻辑过程,它具原子性、一致性、隔离性和持久性的特点。
FDO中事务的概念和RDBMS中事务的概念是基本相同的,和RDBMS中的事务一样,FDO的事务也是关联与一个连接。调用FdoIConnection::StartTransaction()可以启动一个事务,它会返回一个FDO事务FdoTransaction对象,调用FdoITransaction::Commit()可以提交一个事务,在启动事务后针对Data Store所做的所有修改写入数据源中,调用FdoITransaction::Rollback()可以回滚一个事务,在启动事务后针对Data Store所做的所有修改会全部撤销,就像从来没有做过这些修改一样。
FdoPtr<FdoTransaction> transaction; FdoPtr<FdoICommand> command; try { // 启动事务 transaction = connection->BeginTransaction(); ...... command->SetTransaction(transaction); ...... transaction->Commit(); } catch (FdoException* e) { e->Release(); transaction->Rollback(); } |
不过,FDO不支持嵌套事务,这就意味着如果当前连接启动了一个事务,那么在这个事务提交或回滚之前,用户不可以再启动一个新的事务。
需要注意的是事务和长事务不是两个相同的概念,在9.9中我们会介绍长事务。