ThinkGeo.com    |     Documentation    |     Premium Support

Thematic reports based on an external database query

Whats the best way to create a thematic map based on an external database query?


For our Management systems we generally link shape file data to records in a database based on a common ID in the DB and in the attribute table of the shape file. Often we need to create thematic reports based on the results of queries run the the database. What is the best way to achieve this. Thus far in your examples all your thematic reports are based on a query in the attribute table.



Jeremy, 
  
 You can use CustomColumnFetchEvent event to integrate your data to the shape file attributes.  We have a sample HowDoISamples\FeatureLayer\AddMyOwnCustomDataToAFeatureLayer which shows how to do it. 
   
 And there is a known issue about it that the event won’t be raised if you call FeatureSource.GetFeaturesByColumnValues method. We will fix it in the upcoming version which will be released around next week. 
  
 Thanks, 
 ThinkGeo Support 


Thanks I managed to find a similar post by another Jeremy that helped me and I got a test report. The problem I’m facing here is that this seems like an extremely complicated way of creating a thematic report from a database external query. 
  
 Surely instead of actually integrating my data with the shape file attributes it would be better to come up with a way for to create temporary joins to the external database. 
  
 I mean If I have to create say 20 thematic reports for about 12 different shapefiles based of referenced data in the database,  which happens fairly often, my code is going to get very very busy.

Jeremy,



Here I made a wrapper with which, you can use the external database much easier. You can change the code a little bit to meet your requirements.


Here is the code:



 public class CustomDataShapeFileFeatureLayer : ShapeFileFeatureLayer
    {
        private Dictionary<string, string> idLinkFieldDictionary = new Dictionary<string, string>();
        private Dictionary<string, Dictionary<string, string>> customFieldsDictionaries = new Dictionary<string, Dictionary<string, string>>();

        private CustomDataShapeFileFeatureLayer()
            : this(string.Empty)
        { }

        public CustomDataShapeFileFeatureLayer(string shapeFileFilePath)
            : base(shapeFileFilePath)
        {
            FeatureSource.CustomColumnFetch += new EventHandler<CustomColumnFetchEventArgs>(FeatureSource_CustomColumnFetch);
        }

        public void InitDictionaries(string LinkFieldName, DataTable ExternalDataBase, params string[] CustomColumnNames)
        {
            ShapeFileFeatureLayer.BuildRecordIdColumn(this.ShapePathFileName, "RecId", BuildRecordIdMode.DoNotRebuild);

            FeatureSource.Open();
            DataTable dataTable = FeatureSource.ExecuteQuery(string.Format("select RecId, {0} from {1}", LinkFieldName, Path.GetFileNameWithoutExtension(this.ShapePathFileName)));

            foreach (DataRow dataRow in dataTable.Rows)
            {
                idLinkFieldDictionary.Add(dataRow["RecId"].ToString(), dataRow[LinkFieldName].ToString());
            }
            foreach (string customColumnName in CustomColumnNames)
            {
                Dictionary<string, string> dictionary = new Dictionary<string, string>();

                // Here is you own code getting the dictionary from the LinkField To The customColumn you want
                // This sample is using DataTable as the external database. You can change it to consume your own databases.
                foreach (DataRow dataRow in ExternalDataBase.Rows)
                {
                    dictionary.Add(dataRow[LinkFieldName].ToString(), dataRow[customColumnName].ToString());
                }
                customFieldsDictionaries.Add(customColumnName, dictionary);
            }
        }

        void FeatureSource_CustomColumnFetch(object sender, CustomColumnFetchEventArgs e)
        {
            string LinkFieldValue = idLinkFieldDictionary[e.Id];
            if (customFieldsDictionaries[e.ColumnName].ContainsKey(LinkFieldValue))
            {
                e.ColumnValue = customFieldsDictionaries[e.ColumnName][LinkFieldValue];
            }
        }
    }

// Here is how to use this class
 private void DisplayMap_Load(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine(WinformsMap.GetVersion());
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;

            CustomDataShapeFileFeatureLayer worldLayer = new CustomDataShapeFileFeatureLayer(@"..\..\SampleData\Data\Countries02.shp");
            worldLayer.InitDictionaries("CNTRY_NAME", GetTestDataTable(), "History", "Population");
            worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
            worldLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.Country1("History");
            //worldLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.Country1("Population");
            worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

            winformsMap1.StaticOverlay.Layers.Add("WorldLayer", worldLayer);
            winformsMap1.MapBackground.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);
            winformsMap1.CurrentExtent = new RectangleShape(-143.4, 109.3, 116.7, -76.3);

            winformsMap1.Refresh();
        }

        private DataTable GetTestDataTable()
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("CNTRY_NAME");
            dataTable.Columns.Add("History", Type.GetType("System.Int32"));
            dataTable.Columns.Add("Population", Type.GetType("System.Int32"));

            DataRow rowChina = dataTable.NewRow();
            rowChina["CNTRY_NAME"] = "China";
            rowChina["History"] = 5000;
            rowChina["Population"] = 1300000000;
            dataTable.Rows.Add(rowChina);

            DataRow rowUSA = dataTable.NewRow();
            rowUSA["CNTRY_NAME"] = "United States";
            rowUSA["History"] = 250;
            rowUSA["Population"] = 300000000;
            dataTable.Rows.Add(rowUSA);

            return dataTable;
        }


Here is the result:



Thanks,


 


Ben



Thanks Ben, I needed to adjust it to fit my needs, but it appears to work perfectly.

Thanks for your post! Jeremy! 
  
 Let me know if any more questions! 
  
 Thanks. 
  
 Yale