SDE矢ESRI开发的一个空间数据引擎,能够利用文件数据库良好的管理优势去管理数据的图形和属性。AccessDatabase 与后来的 FileGeoDataBase同样也能够很好的管理数据,但是与SDE数据库最大差别是它们不支持多用户同时编辑,也就是SDE的版本技术。虽然大家都知道这些,但是懒羊羊还是要顺便提一下。
很多人第一次接触SDE数据的时候思想可能还停留在对shp文件或是MDB文件的操作上面。事实上它们大部分的操作时一致的,但接入的方式有所不同。由于SDE多了一个版本的控制,所以在数据的载入与打开FeatureClass的时候有很大的差别。下面开始转入正题,讲述一下如何对SDE数据进行操作。
1.
打开SDE数据。
SDE数据一定要使用工作空间工厂去初始化工作空间,在工作空间打开FeatureClass,这是最常规的操作。下面通过一段C#代码连接SDE,打开并返回一个IWorkspace。
public IWorkspace FindWsByDefault()
{
IPropertySet propSet = new PropertySetClass();
propSet.SetProperty("Server", Lan);
propSet.SetProperty("Instance", yangyang);
propSet.SetProperty("Database", "");
propSet.SetProperty("User", user);
propSet.SetProperty("Password", pwd);
propSet.SetProperty("Version", version);
IWorkspaceFactory factory = new SdeWorkspaceFactoryClass();
IWorkspace workspace = factory.Open(propSet, 0);
return workspace;
}
通过上述代码打开了SDE的工作空间,接下来要做的就是获取要编辑的FeatureClass。写一个函数,通过FeatureClass的别名和所在的Dataset返回FeatureClass。做法是先遍历所有的DataSet,找到符合要求的Dataset之后遍历里面的要素,返回与参与别名一致的FeatureClass(顺便说一下,FeatureClass在没有指定别名的时候默认与FeatureClass名称相同)
//查找指定要素
public IFeatureClass FindClassByName(IWorkspace ws, string className, string dsName)
{
IEnumDataset enumDs;
if (dsName != "")
{
enumDs = ws.get_Datasets(esriDatasetType.esriDTFeatureDataset);
IFeatureDataset featureDs = enumDs.Next() as IFeatureDataset;
while (featureDs != null)
{
if (featureDs.Name == dsName)
{
return GetFcFromDataset(featureDs, className);
}
featureDs = enumDs.Next() as IFeatureDataset;
}
}
else
{
enumDs = ws.get_Datasets(esriDatasetType.esriDTFeatureClass);
return GetFcFromEnumDataset(enumDs,className);
}
return null;
}
//在数据集中查找要素类
private IFeatureClass GetFcFromDataset(IFeatureDataset featDs, string className)
{
IFeatureClass featClass;
IFeatureClassContainer fcContainer = featDs as IFeatureClassContainer;
for (int i = 0; i < fcContainer.ClassCount; i++)
{
featClass = fcContainer.get_Class(i);
if (featClass.AliasName == className)
{
return featClass;
}
}
return null;
}
//查找指定要素
public IFeatureClass FindClassByName(IWorkspace ws, string className, string dsName)
{
IEnumDataset enumDs;
if (dsName != "")
{
enumDs = ws.get_Datasets(esriDatasetType.esriDTFeatureDataset);
IFeatureDataset featureDs = enumDs.Next() as IFeatureDataset;
while (featureDs != null)
{
if (featureDs.Name == dsName)
{
return GetFcFromDataset(featureDs, className);
}
featureDs = enumDs.Next() as IFeatureDataset;
}
}
else
{
enumDs = ws.get_Datasets(esriDatasetType.esriDTFeatureClass);
return GetFcFromEnumDataset(enumDs,className);
}
return null;
}
//在数据集中查找要素类
private IFeatureClass GetFcFromDataset(IFeatureDataset featDs, string className)
{
IFeatureClass featClass;
IFeatureClassContainer fcContainer = featDs as IFeatureClassContainer;
for (int i = 0; i < fcContainer.ClassCount; i++)
{
featClass = fcContainer.get_Class(i);
if (featClass.AliasName == className)
{
return featClass;
}
}
return null;
}
//在要素类集合中查找要素类
private IFeatureClass GetFcFromEnumDataset(IEnumDataset enumDs, string className)
{
IFeatureClass featClass = enumDs.Next() as IFeatureClass;
while (featClass != null)
{
if (featClass.AliasName == className)
{
return featClass;
}
featClass = enumDs.Next() as IFeatureClass;
}
return null;
}
//通过要素类名和数据集名在指定的工作空间中寻找要素类
public IFeatureClass FindClassByName(string className, string datasetName)
{
IWorkspace ws = FindWsByDefault();
IFeatureClass featClass = FindClassByName(ws, className, datasetName);
return featClass;
}
特别需要留意的是最后一个函数FindClassByName(,),先是打开SDE的工作空间,在这个工作空间返回符合条件的要素集。通过这样的指向才能对SDE的FeatureClass进行写入和删除的操作。可以把上述代码写成一个静态类,这样就可以很方便的通过数据集名称和要数集别名指向要编辑的FeatureClass了。
值得一提的是,很多新手都没有养成这种良好的习惯,就是先打开工作空间再进行数据的编辑 ,即便是使用shp文件或是MDB数据。他们习惯性的使用MapControl去加载MXD文件,然后在MapControl通过MapControl.get_layer(index)的方法去获取图层,然后将其转为IFeatureLayer或是IFeatureClass进行操作。
事实上,MXD已经不用开发者写一句加载图层的代码就完成了对图层的加载,确实比较方便。但是它有很多看不见的操作没有表现出来,加载完数据之后就把工作空间给自动关闭了。对于shp文件和MDB数据,通过读取地图控件的图层是可以直接达到写入的目的,但一旦有用户进行操作该图层文件就会被锁死,这就是不支持版本技术的表现。而SDE数据由于存在版本(原理不多说了),因此有需要去确保数据的安全性和一致性,必须使用工作空间的形式去打开。如果用读取MapControl图层的方法去获取FeatureClass,实际上获取的是一个没有打开的编辑操作的FeatureClass,在ESRI的帮助文档里面我们不难发现它是只读的,就像在ArcMap里面没有用Editor执行startEdit一样。
private IFeatureClass GetFcFromEnumDataset(IEnumDataset enumDs, string className)
{
IFeatureClass featClass = enumDs.Next() as IFeatureClass;
while (featClass != null)
{
if (featClass.AliasName == className)
{
return featClass;
}
featClass = enumDs.Next() as IFeatureClass;
}
return null;
}
//通过要素类名和数据集名在指定的工作空间中寻找要素类
public IFeatureClass FindClassByName(string className, string datasetName)
{
IWorkspace ws = FindWsByDefault();
IFeatureClass featClass = FindClassByName(ws, className, datasetName);
return featClass;
}
特别需要留意的是最后一个函数FindClassByName(,),先是打开SDE的工作空间,在这个工作空间返回符合条件的要素集。通过这样的指向才能对SDE的FeatureClass进行写入和删除的操作。可以把上述代码写成一个静态类,这样就可以很方便的通过数据集名称和要数集别名指向要编辑的FeatureClass了。
值得一提的是,很多新手都没有养成这种良好的习惯,就是先打开工作空间再进行数据的编辑 ,即便是使用shp文件或是MDB数据。他们习惯性的使用MapControl去加载MXD文件,然后在MapControl通过MapControl.get_layer(index)的方法去获取图层,然后将其转为IFeatureLayer或是IFeatureClass进行操作。
事实上,MXD已经不用开发者写一句加载图层的代码就完成了对图层的加载,确实比较方便。但是它有很多看不见的操作没有表现出来,加载完数据之后就把工作空间给自动关闭了。对于shp文件和MDB数据,通过读取地图控件的图层是可以直接达到写入的目的,但一旦有用户进行操作该图层文件就会被锁死,这就是不支持版本技术的表现。而SDE数据由于存在版本(原理不多说了),因此有需要去确保数据的安全性和一致性,必须使用工作空间的形式去打开。如果用读取MapControl图层的方法去获取FeatureClass,实际上获取的是一个没有打开的编辑操作的FeatureClass,在ESRI的帮助文档里面我们不难发现它是只读的,就像在ArcMap里面没有用Editor执行startEdit一样。
2. 编辑SDE数据
利用上述的方法获取了FeatureClass后就可以用常规的方式对其进行编辑,如delete()和CreateFeature(),或是更改属性值。但是仍然会出现无法编辑数据的现象,这种现象通常提示没有足够的授权去编辑数据,这就涉及到AE对SDE数据编辑的授权,也就是gdbedite的授权(主要是在AE9.2里面)。
关于GDBEdite的授权,懒羊羊已经在之前发过一份比较完整的文档,但还是在这里再归纳一下。
ArcEngine9.2在用户许可上做了很大的改动,应用程序是强制初始化许可,也就是说必须使用LicenseControl或AO接口初始化许可,否则应用程序无法启动。Engine9.1未采取强制初始化许可策略,而是应用程序创建时就初始化标准Engine许可。在一般情况下,我们会用将LicenseControl拖放到主窗体上完成初始化。但当Engine程序需要使用ArcGIS Engine Enterprise Geodatabase(以下简称GDB Update)许可的时候,我们就往往会由于意识不到应该使用该许可,以及无法正确的初始化该许可而陷入麻烦。
对于许可这东西,首先要学会看软件产品的购货单。下表是一份关于ArcEngine9.2的购货单。
2008-3-11 20:21