Select to view content in your preferred language

Please help with ExecuteRelationshipQueryAsync

4622
19
10-07-2010 03:37 PM
RickHendrickson
Occasional Contributor
I can't figure out how to get the results from the related table. Using the query task I can get all the graphics and fields I want by basically using the the spatial query sample found here: http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#SpatialQuery

What is the proper way to get the related table information through the spatial query? For the 'regular query' I think you pass in the geometry from the draw surface. How does the relationshipquery work?

I'm desperate, Thanks!

Rick
0 Kudos
19 Replies
JenniferNery
Esri Regular Contributor
I tried the following code to check that the ObjectIdField in LayerInfo is the same key used to retrieve the graphic ID. It worked on both Map Service and Feature Service you provided, even if they had an alias, they still use field name as key, not the alias.
  public MainPage()
  {
   InitializeComponent();
   FeatureLayer l = new FeatureLayer() { Url = "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/0" };
   l.OutFields.Add("*");
   l.Initialized += l_Initialized;  
   l.Initialize();
  }

  void l_UpdateCompleted(object sender, EventArgs e)
  {
   FeatureLayer l = sender as FeatureLayer;
   l.UpdateCompleted -= l_UpdateCompleted;
   var id = l.LayerInfo.ObjectIdField;
   int objId;
   foreach (var g in l.Graphics)
    objId = Convert.ToInt32(g.Attributes[id]);
  }

  void l_Initialized(object sender, System.EventArgs e)
  {
   FeatureLayer l = sender as FeatureLayer;
   l.Initialized -= l_Initialized;
   l.UpdateCompleted += l_UpdateCompleted;
   l.Update();
  }


If you need to get the alias of a given field, LayerInfo has Fields property, each field will have these information:
http://help.arcgis.com/en/webapi/silverlight/apiref/ESRI.ArcGIS.Client~ESRI.ArcGIS.Client.Field_memb...

string alias;
foreach(var f in l.LayerInfo.Fields)
 alias = f.Alias;


Dave,

Can you try the code above and see if the "bug/feature :)" exist? I can use ObjectIdField to get the object ID from Attributes. Please let me know how I can reproduce it.

Thanks.
0 Kudos
JenniferNery
Esri Regular Contributor

Jenn,

I got yours to work using the code below. It is retrieves the Realted records per individual feature. I was confused because I thought the RelationshipParameter.ObjectIDs was looking for a list of IDs. I was trying to set RelationshipParameter.ObjectIDs = FeatureSet.ObjectIDs but I think there is a conversion issue.

Many Thanks,
Derald


I think your code looks fine already, you did not have to rewrite it to conform to the code I posted earlier. I simply suggested using LayerInfo.ObjectIdField so you don't have to hardcode the key.  You are right that the RelationshipParameter takes an enumerable of ObjectIDs. The code snippet I posted was intended for checking against one ID only and therefore not suitable solution for your application if you need to check against multiple ID's - you would have to tweak it a little bit. And I do not see anything wrong in the code you posted (#7)http://help.arcgis.com/en/webapi/silverlight/apiref/ESRI.ArcGIS.Client~ESRI.ArcGIS.Client.Tasks.Rela...
0 Kudos
DaveTimmins
Deactivated User
Hi Jennifer,

I was doing executing an IdentifyTask which is why the results have the alias set rather than the underlying field name.

If I use

string objectIdFieldAlias = featureLayer.LayerInfo.Fields.Single(field => string.Equals(field.Name, featureLayer.LayerInfo.ObjectIdField)).Alias;

foreach (var relationship in featureLayer.LayerInfo.Relationships)
                {
var objectIds = e.IdentifyResults.Select(item => Convert.ToInt32(item.Feature.Attributes[objectIdFieldAlias])).ToList();


then it works fine.

Also another query. How can you tie the related records back to the original result?  I have the following code to handle the results from ExecuteRelationshipQueryAsync

void ExecuteRelationshipQueryCompleted(object sender, RelationshipEventArgs e)
        {
            if (!e.Result.RelatedRecordsGroup.Any()) return;

            var existingResults = e.UserState as IEnumerable<IdentifyResult>;
            if (existingResults == null) return;
           // RelationshipResult pr = e.Result;

            foreach (var graphic in
                e.Result.RelatedRecordsGroup.Values.SelectMany(graphics => graphics))
            {
               // TODO : get the existing result
               var existingResult = ??????

                foreach(var attribute in graphic1.Attributes)
                {
                    string key = attribute.Key;
                    existingResult.Feature.Attributes.Add(string.Format("{0} (related)", e.Result.Fields.Single(field => string.Equals(field.Name, key)).Alias), attribute.Value);
                }
            } 
        }


The objectid for the original feature matches the value for sf_311_serviceoid in the related result but how do I know that I need to match it against that field?

Cheers,
0 Kudos
JenniferNery
Esri Regular Contributor
Oh I see. You are talking about this thread http://forums.arcgis.com/threads/16331-Results-from-IdentifyTask-are-not-correct-(indexed-by-Field-A... where IdentifyResults use Alias. This bug has been reported to ArcGIS Server Team.

As for your other question, you can use the UserToken parameter of the ExecuteRelationshipQueryAsync to hold the existing graphics.

For example:
// more code here
  qt.ExecuteRelationshipQueryAsync(rp, incidentsLayer.Graphics);
}
private void qt_ExecuteRelationshipQueryCompleted(object sender, RelationshipEventArgs e)
{
 GraphicCollection graphics = e.UserState as GraphicCollection;
// more code here
}


Also, when performing a Query to the Related Table, you don't need to know which field in the table is being matched against the layer's Object ID's. These are the only parameters your application need to know: http://sampleserver3.arcgisonline.com/ArcGIS/SDK/REST/index.html?fsqueryrelated.html
0 Kudos
DaveTimmins
Deactivated User
Hi Jennifer,

OK so the e.Result.RelatedRecordsGroup.Keys are the original feature ObjectID values. Not that clear from the documentation.

Cheers,
0 Kudos
YingLin
Emerging Contributor
I have got the relationship query working. however, having trouble to display the result. from the relationshhip query result, i can get the fileds but where are the values for the fields? I'd like to bind the info from the related table to a datagrid.

the following code return null.
GraphicCollection graphics = e.UserState as GraphicCollection;
0 Kudos
YingLin
Emerging Contributor
Never mind. the objectID wasn't passed properly. it is working now.
0 Kudos
BrandonCales
Regular Contributor
I've tried the above to Query Related Records and just can seem to get it to work. Maybe I'm missing some code or am just not placing it in the right location. I know I have other code in there already and fitting things in seems to always be the problem, however here is my code - if anyone has input, I'd greatly appreciate it.

.xaml - This shows the DataGrid2 that I want to populate with related records

.cs - this shows the code behind. I was trying to place this inline with my ParcelSearch_TaskResultsDataGrid_SelectionChanged. No matter how I add it in, it just doesn't seem to flow or acccept it.
0 Kudos
BrandonCales
Regular Contributor
Got it working, just needs some final cleanup....not sure if its the optimal way, but it works nice.

private void ParcelSearch_TaskResultsDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            foreach (Graphic g in e.AddedItems)
            {
                g.Select();

                if (g.Attributes["OBJECTID"] != null)
                {
                    var id = g.Attributes["OBJECTID"];
                    PARCELIDPASS.Text = string.Format("The ParcelID passed is {0}", id);

                    ParcelSearch_RelatedRecords(null, null, Convert.ToInt32(g.Attributes["OBJECTID"]));
                }
                break;
            }

            foreach (Graphic g in e.RemovedItems)
                g.UnSelect();
        }

        private void ParcelSearch_RelatedRecords(object sender, RoutedEventArgs e, Int32 objectid)
        {
            // QueryTask initialization
            QueryTask ParcelSearch_Related = new QueryTask("{SERVER}/MapServer/79"); //82
            ParcelSearch_Related.ExecuteRelationshipQueryCompleted += ParcelSearch_Related_ExecuteRelationshipQueryCompleted;
            ParcelSearch_Related.Failed += ParcelSearch_Related_Failed;

           //Relationship query
            RelationshipParameter relationshipParameters = new RelationshipParameter()
            {
                ObjectIds = new int[] { objectid },
                OutFields = new string[] { "*" },
                RelationshipId = 1,
                OutSpatialReference = MyMap.SpatialReference
            };

           ParcelSearch_Related.ExecuteRelationshipQueryAsync(relationshipParameters);
        }

        private void ParcelSearch_Related_Failed(object sender, TaskFailedEventArgs args)
        {
            MessageBox.Show("ParcelSearch_Related Failed: " + args.Error);
        }

        void ParcelSearch_Related_ExecuteRelationshipQueryCompleted(object sender, RelationshipEventArgs e)
        {
            RelationshipResult pr = e.Result;
            if (pr.RelatedRecordsGroup.Count == 0)
            {
                ParcelSearch_TaskResultsDataGrid2.ItemsSource = null;
            }
            else
            {
                foreach (var pair in pr.RelatedRecordsGroup)
                {
                    ParcelSearch_TaskResultsDataGrid2.ItemsSource = pair.Value;
                }
            }
        }
0 Kudos
BrandonCales
Regular Contributor
Now I am trying to get this to populate RowDetails rather than a DataGrid in another Panel....if anyone has any ideas.

http://asimsajjad.blogspot.com/2010/04/rowdetailtemplate-of-datagrid-control.html
0 Kudos