I'm attempting to load a large number of features (up to 310k) into a feature class. It is functional at the moment, but speed is a major issue. It takes about .42 seconds per 1000 features. I've seen references to putting the feature class in LoadOnlyMode, but to do so I need to cast to IFeatureClassLoad. This cast always fails.
Here is how the feature class is created. It's nearly ripped straight out of an esri example page. I'm passing in a scratchworkspace created using the ScratchWorkspaceFactory, and thats pretty much the only thing of importance.
public IFeatureClass CreateFeatureClass(IWorkspace workspace, IFeatureDataset featureDataset, Type modelType, String featureClassName, UID CLSID, UID CLSEXT, String strConfigKeyword)
{
if (featureClassName == "") return null;
IFeatureClass featureClass;
var featureWorkspace = (IFeatureWorkspace)workspace;
var dataset = workspace.Datasets[esriDatasetType.esriDTFeatureClass].Next();
while (dataset != null)
{
if (dataset.Name == featureClassName)
{
featureClass = featureWorkspace.OpenFeatureClass(featureClassName);
return featureClass;
}
}
// assign the class id value if not assigned
if (CLSID == null)
{
CLSID = new UID();
}
IObjectClassDescription objectClassDescription = new FeatureClassDescription();
var name = new FeatureClassName {NameString = "Collisions"};
// create the fields using the required fields method
var fields = objectClassDescription.RequiredFields;
IFieldsEdit fieldsEdit = (IFieldsEdit)fields; // Explicit Cast
var typeField = new Field();
var editableField = (IFieldEdit)typeField;
editableField.Name_2 = "TYPE";
editableField.Type_2 = esriFieldType.esriFieldTypeString;
editableField.IsNullable_2 = true;
editableField.AliasName_2 = "TYPE";
editableField.DefaultValue_2 = "Collision";
editableField.Editable_2 = true;
editableField.Length_2 = 100;
fieldsEdit.AddField(typeField);
foreach (var property in modelType.GetProperties().Where(x => x.GetCustomAttributes(typeof(SearchableAttribute), false).Any()))
{
var returnType = property.GetGetMethod().ReturnType;
var searchData = (SearchableAttribute)property.GetCustomAttributes(typeof(SearchableAttribute), false).First();
IField field = new Field();
var fieldEdit = (IFieldEdit)field;
fieldEdit.Name_2 = searchData.DisplayName.Trim();
fieldEdit.Type_2 = returnType == typeof(DateTime) ? esriFieldType.esriFieldTypeDate : esriFieldType.esriFieldTypeString;
fieldEdit.IsNullable_2 = true;
fieldEdit.AliasName_2 = searchData.DisplayName;
fieldEdit.DefaultValue_2 = string.Empty;
fieldEdit.Editable_2 = true;
fieldEdit.Length_2 = 250;
// add field to field collection
fieldsEdit.AddField(field);
}
fields = (IFields)fieldsEdit;
String strShapeField = "";
// locate the shape field
for (var j = 0; j < fields.FieldCount; j++)
{
var field = fields.Field[j];
if (field.Type == esriFieldType.esriFieldTypeGeometry)
{
strShapeField = field.Name;
IGeometryDef geomDef = new GeometryDef();
var geometryDefEdit = (IGeometryDefEdit)geomDef;
geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;
geometryDefEdit.SpatialReference_2 = ArcMap.Document.FocusMap.SpatialReference;
((IFieldEdit)field).GeometryDef_2 = geomDef;
break;
}
}
// Use IFieldChecker to create a validated fields collection.
IFieldChecker fieldChecker = new FieldChecker();
IEnumFieldError enumFieldError = null;
IFields validatedFields = null;
fieldChecker.ValidateWorkspace = (IWorkspace)workspace;
fieldChecker.Validate(fields, out enumFieldError, out validatedFields);
// The enumFieldError enumerator can be inspected at this point to determine
// which fields were modified during validation.
// finally create and return the feature class
if (featureDataset == null)// if no feature dataset passed in, create at the workspace level
{
featureClass = featureWorkspace.CreateFeatureClass(featureClassName, validatedFields, CLSID, CLSEXT, esriFeatureType., strShapeField, strConfigKeyword);
}
else
{
featureClass = featureDataset.CreateFeatureClass(featureClassName, validatedFields, CLSID, CLSEXT, esriFeatureType.esriFTSimple, strShapeField, strConfigKeyword);
}
return featureClass;
}
Once that's done I attempt to load the features from a list of geometry points. The code starts like this:
var featureWorkspace = (IFeatureWorkspace) workspace;
IFeatureClass featureClass = featureWorkspace.OpenFeatureClass(FeatureClassName);
var loader = featureClass as IFeatureClassLoad;
if (loader != null) loader.LoadOnlyMode = true;
var schemaLock = (ISchemaLock) featureClass;
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
where the loader variable is always null. am i missing something obvious? is my feature class not compatible with that interface?
EDIT
In case anyone else comes across this, the problem here was that i was using the ScratchWorkspaceFactory. that class creates a personal geodatabase, and its features cannot be cast to IFeatureClassLoad. FileGDBScratchWorkspaceFactory creates Local file workspaces, and its feature classes can be cast to IFeatureClassLoad. Devil is in the details.