SetName for FeatureLayer, based on QueryDescription?

625
8
Jump to solution
02-07-2021 05:33 AM
ThomasBecker1
Occasional Contributor II

Based on some user settings I am creating QueryFeatureLayers from a database. When the QueryDescription is generated, I can see the UniqueQueryLayerName property seems to be a combination of the database role, and the QueryLayerName property.
The QueryDefinition class does not offer a method to set any of its public properties, and I didn't find a CIM class for the QueryDescription.

Unfortunately, when using the SetDefinition method of  a FeatureLayer the UniqueQueryLayerName property is used in the TOC of my MapView.

If I am correct then I cannot alter the name shown in the QueryDescription, but have to do this after the FeatureLayer received the definition, leading to an undesired behaviour of showing the UniqueQueryLayerName, just to be updated with the "correct" name, that I know already from the start.

 

What I am missing is a property in the QueryDescription where I can set the display name of the layer to be, before I am handing the QueryDescription over to the layer.

0 Kudos
1 Solution

Accepted Solutions
KirkKuykendall1
Occasional Contributor III

I just noticed you can also pass the name to CreateFeatureLayer ... that seems to override the default.

The extent of the querylayer is a bug in my opinion.

This works for me:

 

private void MakeQueryLayer()
{
    var cn = new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
    {
        Instance = "localhost",
        Database = "db1",
        AuthenticationMode = AuthenticationMode.OSA
    };
    Database db = new Database(cn);
    var qd = db.GetQueryDescription(
        "Select objectid, shape from dbo.test2",
        // gets changed to "Dbo.Dbo.MyLyrTmp:
        "MyLyrtmp"); 
    qd.SetObjectIDFields("OBJECTID");
    qd.SetShapeType(GeometryType.Polygon);
    qd.SetSpatialReference(SpatialReferences.WebMercator);

    var fc = db.OpenTable(qd) as FeatureClass;
    var map = MapView.Active.Map;
    var fLayer = LayerFactory.Instance.CreateFeatureLayer(fc, map, 0, "MyLyr");
    // bug: fLayer's extent is incorrect ...
    //MapView.Active.ZoomTo(fLayer);

    // so compute it ...
    MapView.Active.ZoomTo(GetExtentHack(fLayer));
}
private Envelope GetExtentHack(FeatureLayer fLayer)
{
    Envelope extent = null;
    using (var t = fLayer.GetTable())
    {
        using (var cur = t.Search())
        {
            while(cur.MoveNext())
            {
                var geom = cur.Current["Shape"] as Geometry;
                if (extent == null)
                    extent = geom.Extent;
                else
                    extent = extent.Union(geom.Extent);
            }
        }
    }
    return extent;
}

 

 

 

View solution in original post

8 Replies
DanPatterson
MVP Honored Contributor

The only place where I can see where the name of a query layer can be set is within

Make Query Layer (Data Management)—ArcGIS Pro | Documentation


... sort of retired...
0 Kudos
ThomasBecker1
Occasional Contributor II

Nope, I’m not using arcpy... it’s C# 😉

0 Kudos
KirkKuykendall1
Occasional Contributor III

Are you calling GetQueryDescription?  

If so, it appears the second argument passed is used to set the layername.

 

0 Kudos
ThomasBecker1
Occasional Contributor II

I do call GetQueryDescription, and it is correct that it takes the queryLayerName as second argument.

However, the QueryDescription object returned contains the property QueryLayerName, reflecting the second argument given, and a property UniqueQueryLayerName. --> Reference Guide 

The resulting layer does use UniqueQueryLayerName in the TOC, adding the database role used to create the database connection to the front of the QueryLayerName. => [Role].[QueryLayerName]

If the QueryLayerName would be used I could set the desired name without a problem when calling GetDescription...

0 Kudos
KirkKuykendall1
Occasional Contributor III

Did you try setting LayerCreationParams.Name ?

And passing that to CreateLayer<FeatureLayer>

0 Kudos
ThomasBecker1
Occasional Contributor II

Kirk,

I am creating a FeatureClass through

Database.OpenTabel(QueryDescription) as FeatureClass 

and thereafter I create a FeatureLayer in the active map through

LayerFactory.Instance.CreateFeatureLayer(FeatureClass, MapView.Active.Map)

In CreateFeatureLayer I cannot see a possibility to use LayerCreationParams and there is one more issue for me.
Since I create QueryLayers and Esri decided not to set an extent for QueryLayer I am using CIM to crawl into the FeatureLayer and set the extent. Right now I can't see the way to create the Layer based on the FeatureClass.

Here a bit more code to showcase. 'dbSchema' is set before and is a string:

QueryDescription queryDescription =
                            oracleDatabase.GetQueryDescription(querySql, queryLayerName);
                        queryDescription.SetObjectIDFields("OBJECTID");
                        queryDescription.SetShapeType(geomType);
                        SpatialReference spatialReference = MapView.Active.Map.SpatialReference;
                        queryDescription.SetSpatialReference(spatialReference);
                        try
                        {
                            FeatureClass featureClass = oracleDatabase.OpenTable(queryDescription) as FeatureClass;
                            if (featureClass != null && featureClass.GetCount() != 0)
                            {
                                FeatureLayer featureLayer =
                                    LayerFactory.Instance.CreateFeatureLayer(featureClass, MapView.Active.Map);
                                CIMFeatureLayer cimFeatureLayer = featureLayer.GetDefinition() as CIMFeatureLayer;
                                // alter QueryLayerName to reflect correct database scheme
                                cimFeatureLayer.Name = $"{dbSchema}.{queryLayerName}";
                                CIMSqlQueryDataConnection cimConnection = cimFeatureLayer?.FeatureTable.DataConnection as CIMSqlQueryDataConnection;
                                Municipality municipality = SelectedMunicipality;
                                double xMin = Convert.ToDouble(municipality.Xmin);
                                double yMin = Convert.ToDouble(municipality.Ymin);
                                double xMax = Convert.ToDouble(municipality.Xmax);
                                double yMax = Convert.ToDouble(municipality.Ymax);
                                MapPoint minPoint = MapPointBuilder.CreateMapPoint(xMin, yMin, spatialReference);
                                MapPoint maxPoint = MapPointBuilder.CreateMapPoint(xMax, yMax, spatialReference);
                                Envelope municipalityEnvelope =
                                    EnvelopeBuilder.CreateEnvelope(minPoint, maxPoint, spatialReference);
                                if (cimConnection != null) cimConnection.Extent = municipalityEnvelope;

                                featureLayer.SetDefinition(cimFeatureLayer);
                            }
                        }
0 Kudos
KirkKuykendall1
Occasional Contributor III

I just noticed you can also pass the name to CreateFeatureLayer ... that seems to override the default.

The extent of the querylayer is a bug in my opinion.

This works for me:

 

private void MakeQueryLayer()
{
    var cn = new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
    {
        Instance = "localhost",
        Database = "db1",
        AuthenticationMode = AuthenticationMode.OSA
    };
    Database db = new Database(cn);
    var qd = db.GetQueryDescription(
        "Select objectid, shape from dbo.test2",
        // gets changed to "Dbo.Dbo.MyLyrTmp:
        "MyLyrtmp"); 
    qd.SetObjectIDFields("OBJECTID");
    qd.SetShapeType(GeometryType.Polygon);
    qd.SetSpatialReference(SpatialReferences.WebMercator);

    var fc = db.OpenTable(qd) as FeatureClass;
    var map = MapView.Active.Map;
    var fLayer = LayerFactory.Instance.CreateFeatureLayer(fc, map, 0, "MyLyr");
    // bug: fLayer's extent is incorrect ...
    //MapView.Active.ZoomTo(fLayer);

    // so compute it ...
    MapView.Active.ZoomTo(GetExtentHack(fLayer));
}
private Envelope GetExtentHack(FeatureLayer fLayer)
{
    Envelope extent = null;
    using (var t = fLayer.GetTable())
    {
        using (var cur = t.Search())
        {
            while(cur.MoveNext())
            {
                var geom = cur.Current["Shape"] as Geometry;
                if (extent == null)
                    extent = geom.Extent;
                else
                    extent = extent.Union(geom.Extent);
            }
        }
    }
    return extent;
}

 

 

 

View solution in original post

ThomasBecker1
Occasional Contributor II

Cheers Kirk, that works just fine for me as well.


About the extent... I was told in 2019 by ESRI that they did purposely decide against it in QueryLayer objects. Creating the QueryLayer takes not long, gathering all the data laying in the back of it does. Since QueryLayers do reflect the state of the data at the database, they do request the database for the most recent data every time you make it visible in your map.

Hence, I assume what is speaking against the extent in QueryLayer object is performance.