在之前的文章【ArcGIS Pro二次开发】(19):创建要素类(FeatureClass)中有涉及DDL的知识点,随着深入的学习,在这里做一个小总结。
ArcGIS Pro二次开发中的DDL API是一种【数据定义语言】,主要是用于创建、删除、编辑地理数据库以及地理数据库的部件(item),如要素类(FeatureClass)、表(Table)等。
DDL中有一个很重要的类:Description类,即描述类。主要用于指定要创建、修改或删除的数据库存对象。例如,【TableDescription】用来描述一个表。【TableDescription】有多个属性,其中一个属性【FieldDescriptin】则是用来描述字段的构成。
下面是一个【FieldDescriptin】的基本结构,其中【"InspectionDate"】是字段名, 【FieldType.Date】是字段类型,通俗的说,这两个属性相当于字段的主属性,是必须要有的属性,而后面属性列表中的【AliasName】是别名,相当于非必要属性,如果不定义的话,会采用默认值:
- FieldDescription inspectionDateFieldDescription = new FieldDescription("InspectionDate", FieldType.Date)
- {
- AliasName = "Inspection Date"
- };
SchemaBuilder对象(方案构建器?好难翻译),是在地理数据库内部构建的一个对象,用于DDL操作。可以将DDL操作加入SchemaBuilder对象中,按照一定的逻辑顺序执行操作。
例如:先创建SchemaBuilder对象:
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
再将表的创建添加到我们的DDL任务列表中:
schemaBuilder.Create(tableDescription);
注意这里可以添加多个任务到任务列表中。
然后,通过调用 Build方法来执行这组DDL操作。结果可以返回一个bool值,显示是否执行成功。
bool success = schemaBuilder.Build();
以下是官方文档中记录的SchemaBuilder对象的所有成员和方法:
以创建Table首先,创建一系列字段描述对象【FieldDescriptin】。
一个【FieldDescriptin】描述一个字段,一个FeatureClass或Table通常有多个字段,所以我们需要的是多个【FieldDescriptin】的列表。
创建字段可以从头创建,也可以基于已有字段,示例如下:
- // 从头创建一个字段描述
- FieldDescription inspectionDateFieldDescription = new FieldDescription("InspectionDate", FieldType.Date)
- {
- AliasName = "Inspection Date"
- };
-
- // 从已有的字段创建一个域字段描述
- FieldDescription inspectionResultsFieldDescription = FieldDescription.CreateDomainField("InspectionResults", new CodedValueDomainDescription(inspectionResultsDomain));
- inspectionResultsFieldDescription.AliasName = "Inspection Results";
创建所需的字段描述对象集后,下一步是创建一个定义表本身的表描述对象【TableDescription】。
【TableDescription】用于传递给【SchemaBuilder.Create】,通过【SchemaBuilder.Create】实现创建表的功能。
具体流程如下:
- // 收集所有字段描述的列表
- List
fieldDescriptions = new List() - { globalIDFieldDescription, objectIDFieldDescription, inspectionDateFieldDescription, inspectionResultsFieldDescription, inspectionNotesFieldDescription };
-
- // 创建一个【tableDescription】对象来描述要创建的表
- TableDescription tableDescription = new TableDescription("PoleInspection", fieldDescriptions);
-
- // 创建一个【SchemaBuilder】对象
- SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
-
- // 将创建任务添加到DDL任务列表中
- schemaBuilder.Create(tableDescription);
-
- // 执行DDL
- bool success = schemaBuilder.Build();
需要注意的是,上面的流程并没有添加ObjectID字段,执行结果,会自动添加ObjectID字段。
创建FeatureClass遵循与创建Table大致相同的原则。不过需要注意的是,你需要额外创建一个 【ShapeDescription】对象来定义shape字段。
【ShapeDescription】对象可以从一组特性创建,也可以使用现有要素类的【FeatureClassDefinition】创建。在这种情况下,新要素类将继承现有类的相同形状特性。
- // 创建一个【ShapeDescription】对象
- ShapeDescription shapeDescription = new ShapeDescription(GeometryType.Point, spatialReference);
-
- // 或者,可以从另一个要素类创建【ShapeDescription】
- ShapeDescription alternativeShapeDescription = new ShapeDescription(existingFeatureClass.GetDefinition());
最后一步则是创建【FeatureClassDescription】,并使用上面描述的相同模式构建要素类。具体如下:
- // 创建一个【FeatureClassDescription】对象来描述要创建的要素类
- FeatureClassDescription featureClassDescription = new FeatureClassDescription("Cities", fieldDescriptions, shapeDescription);
-
- // 创建一个【SchemaBuilder】对象
- SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
-
- // 将创建任务添加到DDL任务列表中
- schemaBuilder.Create(featureClassDescription);
-
- // 执行DDL
- bool success = schemaBuilder.Build();
以给FeatureClass添加2个新字段为例。
首先,创建一个新的【FeatureClassDescription】。Name属性和【ShapeDescription】就用原有要素的,【FieldDescription】则是在继承原有的基础上,添加2个新字段,然后再替换掉原来的【FieldDescription】进行更新。具体代码如下:
- // 要修改的要素
- string featureClassName = "Parcels";
-
- // 获取待修改要素的【FeatureClassDefinition】
- FeatureClassDefinition originalFeatureClassDefinition = geodatabase.GetDefinition
(featureClassName); - // 获取【FeatureClassDescription】
- FeatureClassDescription originalFeatureClassDescription = new FeatureClassDescription(originalFeatureClassDefinition);
-
- // 定义需要添加的2个字段
- FieldDescription taxCodeDescription = FieldDescription.CreateIntegerField("Tax_Code");
- FieldDescription addressDescription = FieldDescription.CreateStringField("Parcel_Address", 150);
-
- // 将2个新字段添加到【FieldDescription】列表中
- List
modifiedFieldDescriptions = new List(originalFeatureClassDescription.FieldDescriptions); - modifiedFieldDescriptions.Add(taxCodeDescription);
- modifiedFieldDescriptions.Add(addressDescription);
-
- // 使用新添加的字段创建一个【FeatureClassDescription】
- FeatureClassDescription modifiedFeatureClassDescription = new FeatureClassDescription(originalFeatureClassDescription.Name, modifiedFieldDescriptions, originalFeatureClassDescription.ShapeDescription);
-
- SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
-
- // 更新【Parcels】要素
- schemaBuilder.Modify(modifiedFeatureClassDescription);
- bool modifyStatus = schemaBuilder.Build();
- // 如果出现错误,返回
- if (!modifyStatus)
- {
- IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
- }
重命名表格或要素类,请创建与要重命名的表格或要素类匹配的【Description】对象。然后在【SchemaBuilder】类上调用Rename方法,代码如下:
- // 定义原Name和要重命名的Name
- string tableToBeRenamed = "Original_Table";
- string tableRenameAs = "Renamed_Table";
- // 获取要重命名的表的【TableDefinition】
- TableDefinition tableDefinition = geodatabase.GetDefinition
(tableToBeRenamed); -
- SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
-
- // 调用Rename方法即可重命名
- schemaBuilder.Rename(new TableDescription(tableDefinition), tableRenameAs);
- // 执行DDL
- schemaBuilder.Build();
这里添加字段的方法和上面第2节使用的方法大致相同。
- // 从现有表中获取【TableDescription】
- TableDescription tableDescription = new TableDescription(parcelTableDefinition);
-
- // 获取【FieldDescriptions】
- List
fieldDescriptions = new List (tableDescription.FieldDescriptions); -
- // 往【FieldDescriptions】中添加字段
- fieldDescriptions.Add(FieldDescription.CreateIntegerField("FloodRiskScale"));
-
- // 修改【TableDescription】
- TableDescription modifiedTableDescription = new TableDescription(tableDescription.Name, fieldDescriptions);
-
- // 更新【TableDescription】
- schemaBuilder.Modify(modifiedTableDescription);
-
- // 执行DDL
- schemaBuilder.Build();
删除字段方法如下:
- // 从现有表中获取【TableDescription】
- TableDescription tableDescription = new TableDescription(parcelTableDefinition);
-
- // 定义要保留的字段
- FieldDescription taxFieldToBeRetained = new FieldDescription(parcelTableDefinition.GetFields().First(f => f.Name.Equals("TaxCode")));
- List
fieldsToBeRetained = new List { taxFieldToBeRetained }; -
- // 修改【TableDescription】
- TableDescription modifiedTableDescription = new TableDescription(tableDescription.Name, fieldsToBeRetained);
-
- // 更新【TableDescription】
- schemaBuilder.Modify(modifiedTableDescription);
-
- // 执行DDL
- schemaBuilder.Build();
可以使用SchemaBuilder.Modify(TableDescription、String、FieldDescription)方法修改表或要素类中某些现有字段的字段属性,如名称、别名、长度和类型。
但是需要注意,有些固有字段是不能修改的,如ObjestID,Shape_Area等。
还有就是别名的最大长度为255个字符,地理数据库中不允许使用空字符串作为别名。
示例代码如下:
- // 获取要修改的字段【Parcel_Address】
- Field parcelAddress = featureClassDefinition.GetFields().FirstOrDefault(f => f.Name.Contains("Parcel_Address"));
-
- // 更新字段的别名和长度
- FieldDescription newParcelFieldDescription = new FieldDescription(parcelAddress)
- {
- AliasName = "Physical Property Address",
- Length = 250
- };
-
- // 设置默认的字段值
- newParcelFieldDescription.SetDefaultValue("123 Main St");
-
- schemaBuilder.Modify(new TableDescription(featureClassDefinition), parcelAddress.Name, newParcelFieldDescription);
- schemaBuilder.Build();
要删除FeatureClass、Table只需要使用【SchemaBuilder.Delete】方法即可,其它的步骤和上面都差不多。
- // 获取【tableDescription】
- TableDescription tableDescription = new TableDescription(table.GetDefinition());
-
- // 创建【SchemaBuilder】对象
- SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
-
- // 调用【Delete】方法
- schemaBuilder.Delete(tableDescription);
-
- // // 执行DDL
- bool success = schemaBuilder.Build();
创建和删除文件地理数据库遵循的模式与其他DDL操作略有不同。可以调用【SchemaBuilder】类上的【CreateGeodatabase】和【DeleteGeodatabase】方法来创建和删除文件地理数据库。
这两个方法都以【FileGeodatabaseConnectionPath】作为参数,即文件路径。
需要注意的是,如果文件地理数据库正在使用中,则无法将其删除。所有对文件地理数据库的执行工作都必须在删除前完成。
- // 创建【SchemaBuilder】对象
- SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
-
- // 调用【CreateGeodatabase】方法创建数据库
- schemaBuilder.CreateGeodatabase(GeodatabasePath);
-
- // 执行DDL
- bool success = schemaBuilder.Build();