Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I'm sorry, I know this is a pretty simple question but am having trouble getting this to work. Basically, I have 2 linear featureclasses and they both have the same fields and spatial reference. FC1 has 675 records and FC2 only has 505 records. So how can I check what Prop_ID(s) are missing from FC2? I have some code that will copy the missing record from FC1 to FC2 but must first determine the missing Prop_ID.

many thanks

share|improve this question
    
Is Prop_ID the unique identifier field in the two Feature Classes? –  Seth P. May 25 '11 at 18:33
1  
If the featureclasses are in a dbms and are not versioned, have you tried SQL with a NOT IN clause? –  Kirk Kuykendall May 25 '11 at 18:50
    
@Seth- yes Prop_ID is the unique identifier –  Josh May 25 '11 at 19:54
    
do you mean the prop_id is the object id? because unless you have your own uid field the object id can change upon export or edit. –  Brad Nesom May 25 '11 at 20:39
    
Hi Brad, Seth, Kirk, and Jay. I think Jay and Kirk's suggestion on using "NOT IN" is probably the best way to approach this but since I don't know how to implement this in C# I was able to get Kirk's code working for geatureclasses instead. Thank you all for your help. –  Josh May 25 '11 at 20:49
add comment

2 Answers 2

up vote 4 down vote accepted

Since you tagged this question with arcobjects and c#, and since not all geodatabases support the SQL IN with a subquery, the following untested code shows how you could do this with System.Collections.Hashtable.

private List<int> Diff(ITable table1, ITable table2, string idfldName)
{
    // return the oid of each row in table1 whose id doesn't appear in table2
    var outList = new List<int>();

    var ht1 = HashRows(table1, idfldName);
    var ht2 = HashRows(table2, idfldName);
    foreach (object key in ht1.Keys)
    {
        if (!ht2.ContainsKey(key))
            outList.Add((int)ht1[key]);
    }
    return outList;
}

private Hashtable HashRows(ITable table, string idField)
{
    Hashtable ht = new Hashtable();
    ICursor cur = table.Search(null, true);
    try
    {
        int idx = table.FindField(idField);
        if (idx == -1)
            throw new Exception("Field not found: " + idField);
        IRow row;
        while ((row = cur.NextRow()) != null)
        {
            if(!ht.ContainsKey(row.get_Value(idx)))
                ht.Add(row.get_Value(idx),row.OID);
            else
                throw new Exception("duplicate key encountered at OID = " + row.OID);
        }
    }
    catch
    {
        throw;
    }
    finally
    {
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cur);
    }
    return ht;
}
share|improve this answer
    
@Kirk- can this work for 2 featureclasses? I see how you are passing in 2 itables instead. –  Josh May 25 '11 at 20:12
    
I was able to get this working. thanks Kirk –  Josh May 25 '11 at 20:50
    
Don't want to nitpick, but I'd prefer System.Collections.Generic.Dictionary<TKey, TValue> over System.Collections.Hashtable any time of the day. –  Petr Krebs May 26 '11 at 6:34
    
I read somewhere the hashtable is a lot faster, no? –  Kirk Kuykendall May 26 '11 at 13:10
    
hashtable and dictionary<,> offer similar performance. The greatest benefit of the generic version is of course not having to throw casts around the place. See stackoverflow.com/questions/1089132/… –  cfern Jun 8 '11 at 9:23
add comment

This is DBMS specific, so it may not work if you are on a filegeodb, but you could use something like PROP_ID NOT IN (select PROP_ID from FC1) in a query filter if your featureclasses aren't versioned.

This is really rough since I'm not at my workstation. This assumes you already have your IFeatureClass reference:

IQueryFilter queryFilter = new QueryFilterClass();
queryFilter.WhereClause = "PROP_ID NOT IN (select PROP_ID from FC1";

IFeatureCursor cursor = featureClass.Search(queryFilter,true);

IFeature feature = null;

  while ((feature = cur.NextFeature()) != null)
    {
        feature.get_Value(idx); // use the FindField to get idx like in Kirk's code sample
    }

Not sure which .NET framework you are in, but if here is an extension method:

    /// <summary>
    /// Gets the field values for a featureclass
    /// </summary>
    /// <param name="featureclass">The feature class.</param>
    /// <param name="fieldName">Name of the field.</param>
    /// <param name="whereClause">where clause for queryfilter</param>
    /// <returns>dictionary of int, object where int is the OBJECTID and object is the field value</returns>
    public static Dictionary<int, object> GetFieldValues(this IFeatureClass featureclass, string fieldName, string whereClause)
    {
        Dictionary<int, object> dictionary = new Dictionary<int, object>();

        IQueryFilter filter = new QueryFilterClass();
        filter.SubFields = string.Format("{0},{1}", featureclass.OIDFieldName, fieldName);
        filter.WhereClause = whereClause;

        int fieldIndex = featureclass.Fields.FindField(fieldName);
        if (fieldIndex > -1)
        {
            IFeatureCursor cursor = null;

            try
            {
                cursor = featureclass.Search(filter, true);
                IFeature feature = null;

                while ((feature = cursor.NextFeature()) != null)
                {                        
                    dictionary.Add(
                        feature.OID,
                        feature.get_Value(fieldIndex).Equals(System.DBNull.Value) ? null : feature.get_Value(fieldIndex));
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
            }
        }

        return dictionary;
    }

And you can use it like this:

        Dictionary<int, object> featClassFieldvalues = fc1.GetFieldValues("PROP_ID", string.Empty);

        Dictionary<int, object> featClassFieldvalues2 = fc2.GetFieldValues("PROP_ID",string.Empty);

        var v = featClassFieldvalues.Values.Except(featClassFieldvalues2.Values);
share|improve this answer
    
@Jay- how can I write what you suggested in C#? –  Josh May 25 '11 at 20:39
    
@Josh- updated from memory -- no guarantee. –  Jay Cummins May 25 '11 at 22:11
    
Good usage of subfields, this should outweigh any performance advantage of using hashtable (if there is any). –  Kirk Kuykendall May 26 '11 at 13:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.