2

I'm getting strange behaviour reading added features from a feature class while within an edit session. The feature class is in a personal geodatabase and is open in the map control in an ArcEngine application. The user selects a feature in the layer and splits it in 2 with a polyline. The code then modifies an attribute of the new features to be a unique int (a surrogate object id, really):

ISet features = feature.Split(splitLine);

//let's say the original feature had surrogate id 1,
//so both split features have surrogate id 1 at the moment

//let the next available surrogate id be 6
IFeature splitFeature = (IFeature)(features.Next());
splitFeature.set_Value(surrogateIdOrdinal, 6);
splitFeature.Store();
splitFeature = (IFeature)(features.Next());
splitFeature.set_Value(surrogateIdOrdinal, 7);
splitFeature.Store();

At this point we also add some rows to auditing tables (mapping the original pre-split surrogate id mapping to the two new surrogate ids and so on) and update related tables that relate on the surrogate id to have a row for each new feature.

This is all performed in an edit operation which is then stopped. The edit session remains open to provide undo/redo.

In another edit operation we then search for the newly added features by surrogate id:

IQueryFilter filter = new QueryFilterClass();
filter.WhereClause = surrogateIdField + " = " + surrogateId;
return fClass.FeatureCount(filter) > 0;

Say, for example, that one of the newly added features had object id 100 and surrogate id 6, filtering by the surrogate id being equal to 6 will return a count of 0. However, filtering by object id being equal to 100 will return a count of 1. This happens with IFeatureClass.Search as well (returning no rows when there should be one). If we pass null as the filter to Search and iterate the rows, we find a row with surrogate id equal to 6.

Additionally, checking the edit changes in the edit session finds 2 inserted rows, one of which has object id 100 and surrogate id 6:

IDataChangesEx changes = workspace.get_EditDataChanges(esriEditDataChangesType.esriEditDataChangesWithinSession);
IDifferenceCursorEx = changes.ExtractEx("fclass", esriDifferenceType.esriDifferenceTypeInsert);
IRow sourceRow, differenceRow;
ILongArray differenceIndices;
int oid;
differenceCursor.Next(out oid, out sourceRow, our differenceRow, out differenceIndices);
//sourceRow has OID 100 and surrogate id 6

I am unable to replicate this behaviour in a simpler project (both filter where clauses return the new row), so there's obviously something else that has been done that prevents the non-OID filter from returning the row, but I can't find anything that should do that (the only other arcobjects interactions in the process are QueryFilter searches, updating of row attributes, and inserting new rows to related and auditing tables where needed).

UPDATE: I've done some more testing and the effect is observed immediately after the split is performed:

public bool existsBySubsId(int subsId, out bool foundInAllRows)
{
    foundInAllRows = false;
    IFeatureClass fClass = featureWorkspace.OpenFeatureClass("fclass");
    int subsIdOrd = fClass.FindField("SUBSID");
    IFeatureCursor cursor = fClass.Search(null, true);
    IFeature feat;
    while ((feat = cursor.NextFeature()) != null)
    {
        int foundSubsId = (int)feat.get_Value(subsIdOrd);
        if(foundSubsId == subsId)
        {
            foundInAllRows = true;
            break;
        }
    }

    IQueryFilter filter = new QueryFilterClass();
    queryFilter.WhereClause = "SUBSID = " + subsId;
    return fClass.FeatureCount(filter) > 0;
}

//feature has SUBSID = 5
public ISet SplitFeature(IFeature feature, IPolyLine splitLine)
{
    ISet splitFeatures;
    bool subsIdExists, subsIdFoundInAllRows;
    subsIdExists = existsBySubsId(5, out subsIdFoundInAllRows);
    //both subsIdExists and subsIdFoundInAllRows are true
    splitFeatures = feature.Split(splitLine);
    subsIdExists = existsBySubsId(5, out subsIdFoundInAllRows);
    //subsIdExists is false, subsIdFoundInAllRows is true
    return splitFeatures;
}

So before splitting it finds at least one row with SUBSID = 5 both by using queryfilter/FeatureCount and by iterating over all rows without a QueryFilter manually checking the SUBSID. After splitting, FeatureCount no longer finds the rows with SUBSID = 5, but iterating all rows without a QueryFilter does find a row.

UPDATE 2: After some more testing I've found that replacing the split with other operations has varying results.

If I change the split to an insert using IFeatureClass.CreateFeature() and Feature.Store(), it exhibits the same non-queryable behaviour. If I use an insert cursor and a feature buffer, it behaves correctly and the newly added SUBSID is queryable.

If I change the split to an update using either IFeature.Store or IFeatureCursor.UpdateFeature, it exhibits the non-queryable behaviour with a twist that the old SUBSID is still findable with a QueryFilter and returns the row with the new SUBSID. So I'm updating a row's SUBSID from 1 to 2, leaving no rows with 1 as their SUBSID, and then subsequently doing:

IQueryFilter filter = new QueryFilterClass();
filter.WhereClause = "SUBSID = 1";
IFeatureCursor cursor = featureClass.Search(filter, true);
IFeature feat = cursor.NextFeature();
//feat is not null even though there are no features with SUBSID == 1
int subsId = (int)feat.get_Value(feat.Fields.FindField("SUBSID"));
//subsId is 2

When the application first starts, split and update work correctly, but as soon as a feature that has been returned from anything other than an update cursor has Store called, the non-querying behaviour starts to occur. After Store has been called, split will always create two non-queryable polygons. I've tried removing every call to Store from the application, but some features do not come from cursors (e.g. selections from the map) when they are being updated. Additionally, it appears that calling Split triggers the issue as well so I guess that's doing a Store behind the scenes?

The link between calling Store and the error occurring seems similar to what might happen with an ArcView licence (with Store, edit sessions, and relationship classes not working), but this is an ArcEngine licence with the geodatabase update extension. The feature class is referenced in several relationship classes, but I've been trying to replicate this using the exact same PGDB in a new ArcEngine project and cannot reproduce it.

Any help, or even avenues for investigation, are gratefully received. This one really has me baffled.

  • Could the problem be as simple as using the correct Field name delimiters? You state you are using a personal geodatabase so the delimiters are [] so something like filter.WhereClause = "[" & surrogateIdField & "] = " & Cstr(surrogateId) – Hornbydd Jan 14 '15 at 21:03
  • Unfortunately that didn't work. If the field name wasn't matching, though, wouldn't it have given an error? Though I could see it maybe working on validation and querying against the db (which doesn't have the new rows yet) but not matching against the in-memory edit session rows because of case sensitivity or something. Unfortunately, this was not the case and it still returns no rows even with delimiters and exact casing. – Martin Wilkerson Jan 15 '15 at 11:33
  • Have you tried a Try Catch Loop, looking for ComExceptions specifically? I think youll find your answer there. – user17260 Dec 15 '17 at 18:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.