Friday, October 9, 2009

Data Tranfer between workspaces

Preface

Copying data between workspaces is a day-to-day piece of work for ArcGIS users, and so for developers.

In this article I’m going to show you how to use ArcObjects to copy data between different workspaces.

Actually there are many approaches for doing so in ArcGIS, each of them has some limitation in its functionality, after doing some research on the subject I found that you could transfer data between workspaces in one of these ways:

1- Write a manual code to do the operation from scratch.

2- Use the IDataset.Copy().

3- Use Geoprocessor object.

4- Use IFeatureDataConverter interface.

5- Use IGeoDBDataTransfer interface.

So as I said each of the above ways has some limitation in functionality, IDataset.Copy as the help says: “should only be used with datasets from file-based data sources, such as shapefiles and coverages”, Geoprocessor is great but I had some difficulties passing an ArcSDE workspace as a parameter to the copy tool, that keep IFeatureDataConverter and IGeoDBDataTransfer, I tried both of them and they seem to work fine. So we will see now two examples on using IFeatureDataConverter and IGeoDBDataTransfer to copy a feature class from workspace to another.

A. Using IFeatureDataConverter

The interface IFeatureDataConverter has only one implementer class which is FeatureDataConverter, the beauty of this class is that it checks for field naming conflicts and removes them using IFieldChecker.

I’ll try to make my examples simple and clear, and this is difficult when working with ArcObjects (You know).

So our main goal is to copy a feature class from one workspace to another using IFeatureDataConverter using ConvertFeatureClass method.

This method is defined like:

public IEnumInvalidObject ConvertFeatureClass (

IFeatureClassName InputDatasetName,

IQueryFilter InputQueryFilter,

IFeatureDatasetName outputFDatasetName,

IFeatureClassName outputFClassName,

IGeometryDef OutputGeometryDef,

IFields OutputFields,

string configKey,

int FlushInterval,

int parentHWND

);

What is important to us is underlined.

So the main steps for this approach would be:

1- Get the FeatureClassName from input FeatureClass.

2- Get the WorkspaceName from input FeatureClass to be used with IFieldChecker later.

3- Create new FeatureClassName with the new name and supplied workspace.

4- Get the fixed Fields from FieldChecker.

5- Call the ConvertFeatureClass method of FeatureDataConverter.

Code

public void ConvertFeatureClass(IFeatureClass inFeatureClass, IWorkspace outWorkspace, string newName)
{
// get FeatureClassName for input
IDataset inDataset = inFeatureClass as IDataset;
IFeatureClassName inFeatureClassName = inDataset.FullName as IFeatureClassName;
IWorkspace inWorkspace = inDataset.Workspace;

// get WorkSpaceName for output
IDataset outDataset = outWorkspace as IDataset;
IWorkspaceName outWorkspaceName = outDataset.FullName as IWorkspaceName;

// Create new FeatureClassName
IFeatureClassName outFeatureClassName = new FeatureClassNameClass();
// Assign it a name and a workspace
IDatasetName datasetName = outFeatureClassName as IDatasetName;
datasetName.Name = newName == "" ? (inFeatureClassName as IDatasetName).Name : newName;
datasetName.WorkspaceName = outWorkspaceName;

// Check for field conflicts.
IFieldChecker fieldChecker = new FieldCheckerClass();
IFields inFields = inFeatureClass.Fields;
IFields outFields;
IEnumFieldError enumFieldError;
fieldChecker.InputWorkspace = inWorkspace;
fieldChecker.ValidateWorkspace = outWorkspace;
fieldChecker.Validate(inFields, out enumFieldError, out outFields);
// Check enumFieldError for field naming confilcts

//Convert the data.
IFeatureDataConverter featureDataConverter = new FeatureDataConverterClass();
featureDataConverter.ConvertFeatureClass(inFeatureClassName, null, null,
outFeatureClassName, null, outFields, "", 100, 0);
}


The above function converts (Copy) the supplied feature class to the targeted workspace, if no name provided it will use the name of the supplied feature class.

B. Using IGeoDBDataTransfer

The use of GeoDBDataTranfer is used in ArcCatalog for copy and paste oprations, so I really prefer this way.

The main steps for this approach would be:

1- Get the name Objects from input.

2- Prepare Transfer parameters (IEnumName and IName).

3- Generate Name Mappings.

4- Do the transfer.

Code:

private void transferData(IFeatureClass sourceFeatureClass, IWorkspace targetWorkspace)
{
// Get Name Objects
IDataset ds1 = sourceFeatureClass as IDataset;
IDataset ds2 = targetWorkspace as IDataset;
IFeatureClassName fcName = ds1.FullName as IFeatureClassName;
IWorkspaceName2 targetWSName = ds2.FullName as IWorkspaceName2;

// Prepare Transfer Parameters
IName fromName = fcName as IName;
IName toName = targetWSName as IName;

// Prepare input enum and add fromName to it
IEnumName fromNameEnum = new NamesEnumerator();
IEnumNameEdit fromNameEnumEdit = (IEnumNameEdit)fromNameEnum;
fromNameEnumEdit.Add(fromName);

// Generate name Mapping
IGeoDBDataTransfer transferer = new GeoDBDataTransferClass();
IEnumNameMapping fromMapping;
bool v = transferer.GenerateNameMapping(fromNameEnum, toName, out fromMapping);

// Do The Transfer
transferer.Transfer(fromMapping, toName);
}


Note: The above approach doesn’t support old file based Workspaces (Shape Files, Coverages), to copy those you can use IDataset.Copy method.

Note: The class GeoDBDataTransfer implements the interface IFeatureProgress so you can show a user a feedback about the copy operation progress, but although they say in the help that Step is an event of type some delegate you can’t use this interface in .net because it is not supported.


I hope this was useful for you, and hope to see some feed back.

6 comments:

Anonymous said...

Dear Author www.arcgisserverblog.com !
I apologise, but, in my opinion, you commit an error. Let's discuss. Write to me in PM, we will communicate.

Kumait Muhammad said...

what is the error?, all the above code is tested man, actually I got it out from VS.

Anonymous said...

Dear Author www.arcgisserverblog.com !
I consider, that you are not right. Write to me in PM, we will communicate.

Anonymous said...

I want to quote your post in my blog. It can?
And you et an account on Twitter?

Anonymous said...

I want to quote your post in my blog. It can?
And you et an account on Twitter?

Anonymous said...

I want to quote your post in my blog. It can?
And you et an account on Twitter?