I’m attempting to write a script that will check a number of tables within a service for a match to the service’s filter (Only ever 1 filter per table, but filters may contain wildcards).
As of now I iterate through each child element (Finding the related Protocol), then iterate through each filter within the child element, then for each filter I lookup the table using Protocol.FindAssociatedTableParameter, then lookup the DisplayKey (or PrimaryKey) using Protocol.FindAssociatedDisplayKeyColumn (or …PrimaryKeyColumn), then I use Column.Lookup() to lookup the filter on the Display or Primary Key column for one or more matches.
This is not working because most of the filters are for DisplayKeys and I cannot figure out how to find a DisplayKey when given a table. I see the general rule is Table ID + 2, but this is not always the case (Specifically with Cisco DCM which is one of the elements this is intended to be used with).
After digging I’ve noticed that protocol.FindAssociatedDisplayKeyColumn(tableID), will typically return the Primary Key and not the Display Key (Except in the case of Cisco DCM). Digging into the Protocols, it seems that most Display Keys are not marked as Display Keys (Specifically I checked are TAG Media Control System and TechEx MWCore).
Is there any way to consistently return the Display Key?
Here is the function in its current state (Which incorrectly fails to find DisplayKeys in 99% of situations):
private string CheckService(IDmsService dmsService)
{
List<string> missing = new List<string>();Service service = engine.FindService(dmsService.AgentId, dmsService.Id);
ServiceInfoParams[] elements = service.ServiceInfo.ServiceParams;if (elements == null)
{
return “No children”;
}
foreach (var childElement in elements)
{
// Connect to child Element & Protocol
IDmsElement element = dms.GetElement(new DmsElementId(childElement.DataMinerID, childElement.ElementID));
var protocol = engine.FindElement(childElement.DataMinerID, childElement.ElementID).Protocol;HashSet<int> seenTables = new HashSet<int>();
ServiceParamFilter[] filters = childElement.ParameterFilters;foreach (ServiceParamFilter filter in filters)
{
// Get info about filter Parameter from Protocol
var paramInfo = protocol.FindParameter(filter.ParameterID);
var tableInfo = protocol.FindAssociatedTableParameter(filter.ParameterID);
if (tableInfo == null || seenTables.Contains(tableInfo.ID))
{
// Is not a table OR already seen
continue;
}seenTables.Add(tableInfo.ID);
if (string.IsNullOrEmpty(filter.FilterValue))
{
// Table has no filter
missing.Add($”{childElement.Alias}.{tableInfo.Name}”);
continue;
}// Get Index column based on FilterType (Display Key vs Primary Key)
var indexKey = (int)filter.FilterType == DisplayFilter ? protocol.FindAssociatedDisplayKeyColumn(tableInfo) : protocol.FindAssociatedPrimaryKeyColumn(tableInfo);
var column = element.GetTable(tableInfo.ID).GetColumn<string>(indexKey.ID);// Lookup rows matching the given filter
string[] rows = column.Lookup(filter.FilterValue);
//engine.GenerateInformation($”FOUND {rows.Length} ROWS for {childElement.Alias}.{tableInfo.Name} ({paramInfo.Name}) [{tableInfo.ID}/{indexKey.ID}/{indexKey.Name}] = {filter.FilterValue}”);
if (rows.Length < 1)
{
// No rows found
missing.Add($”{childElement.Alias}.{tableInfo.Name}”);
}
// Otherwise this table is good to go!
}
}return missing.Count != 0 ? $”Missing…\n – {string.Join(“\n – “, missing)}” : “OK”;
}

Hi Nick,
Instead of:
var indexKey = (int)filter.FilterType == DisplayFilter ? protocol.FindAssociatedDisplayKeyColumn(tableInfo) : protocol.FindAssociatedPrimaryKeyColumn(tableInfo);
var column = element.GetTable(tableInfo.ID).GetColumn<string>(indexKey.ID);
Have you tried:
var column = (int)filter.FilterType == DisplayFilter ? element.GetTable(tableInfo.ID).GetDisplayKeys() : element.GetTable(tableInfo.ID).GetPrimaryKeys();
regards,

I did, however I'm attempting to get the ID of the DisplayKey column to use in a query (Since my filters will have wildcards in them).
These functions are returning an array of parameter values, but don't seem to have reference to which column they are coming from.
Just in case anyone is looking, I was unable to figure this out, so I created a workaround function below.
This is not an ideal solution since it relies on the column names having [IDX] in them and can be slow. So if anyone knows a more direct way to do this, let me know.
Method to copy:
using Skyline.DataMiner.Net.Messages;
using SLParameterInfo = Skyline.DataMiner.Net.Messages.ParameterInfo;
using SLFilterType = Skyline.DataMiner.Net.Messages.FilterType;
using SLProtocol = Skyline.DataMiner.Net.Messages.GetProtocolInfoResponseMessage;/// <summary>
/// Lookup the specified table index (Cached).
/// </summary>
/// <param name=”protocol”>Protocol of Element containing the table.</param>
/// <param name=”tableInfo”>ParameterInfo of table to lookup indexes for.</param>
/// <param name=”indexType”>Type of Index to lookup (Display/Primary)</param>
/// <returns>ParameterID of the specified index.</returns>
private int GetIndexId(SLProtocol protocol, SLParameterInfo tableInfo, SLFilterType indexType)
{
// Get Primary Key (easy)
var primaryKey = protocol.FindAssociatedPrimaryKeyColumn(tableInfo);
if ((int)indexType != (int)SLFilterType.Display)
{
return primaryKey.ID;
}// Get Display Key (simple method)
var displayKey = protocol.FindAssociatedDisplayKeyColumn(tableInfo);
if (displayKey != null && displayKey.ID != primaryKey.ID)
{
return displayKey.ID;
}// If the simple method fails, look for [IDX] in the column short names
foreach (TableColumnDefinition col in tableInfo.TableColumnDefinitions)
{
var colInfo = protocol.FindParameter(col.ParameterID);
if (colInfo == null) { continue; } // Handle missing parameters
if (colInfo.DisplayName.Contains(“[IDX]”))
{
return colInfo.ID;
}
}// Fallback on Primary Key
return primaryKey.ID;
}
Sample usage:
var protocol = engine.GetDummy(“dummy”).Protocol;
var tableInfo = protocol.FindAssociatedTableParameter(anyParamId);
int tableIndexParamId = GetIndexId(protocol, tableInfo, SLFilterType.Display);
Also any advice on how to improve the performance is recommended, such as where bottlenecks are so I can implement caching.