Skip to content

platform sdk entity loading cache and query behavior

Andre Lafleur edited this page Oct 8, 2026 · 4 revisions

Understanding entity loading, cache behavior, and query options

The Platform SDK has multiple ways to find and read Security Center entities. These APIs look similar, but they do different work. Use this page to choose between EntityConfigurationQuery, Engine.GetEntity, Engine.GetEntities, GuidsOnly, EntityGuids, EntityTypeFilter, DownloadAllRelatedData, and StrictResults.

Query result rows, locally available entity data, and Entity objects are distinct concepts. Keep them separate when you design a loading pattern.

The examples assume that engine is a connected Engine instance. Methods that receive candidateGuids or cardholderGuids require the entity identifiers that your application must process.

Distinguish query results, local data, and entity objects

Entity loading involves three distinct concepts. Each answers a different question.

Query result rows

A report query returns a DataTable. For an EntityConfigurationQuery, each row usually identifies an entity that matched the query filters. The result rows are the output of the query. They are not the same thing as the Engine cache.

StrictResults controls the guarantee on those rows. It does not control which related data the SDK loads locally.

Entity data available to the Engine

When a query loads entity data, the Engine can use that data locally. That data can include common fields, type-specific fields, relationship data, or related entities, depending on the query options.

For example, an EntityConfigurationQuery for cardholders with DownloadAllRelatedData = true loads cardholder data and also loads data for related entities such as assigned credentials.

Entity objects returned to your code

Your code works with SDK objects such as Camera, Cardholder, Partition, and Entity. You retrieve those objects with methods such as Engine.GetEntity and Engine.GetEntities.

A query can make entity data available before your code retrieves the corresponding Entity object. Engine.GetEntities returns objects for entity data that is already available locally. Engine.GetEntity uses local data when available and can query the Directory for a missing entity.

How the main APIs differ

Each API has a specific job. Choose the API based on whether you need to discover entities, load entity data, retrieve Entity objects, or avoid server calls.

API or option What it does
EntityConfigurationQuery Finds entities and loads entity data according to the filters and options on the query.
EntityTypeFilter Limits the query to one or more entity types or subtypes.
EntityGuids Limits the query to a known set of candidate entity GUIDs.
GuidsOnly = true Returns matching GUIDs without loading entity data.
DownloadAllRelatedData = true Loads relationship data and related entities for the matched entities.
StrictResults = true Guarantees that query result rows contain only entities that matched the query filters.
Engine.GetEntity(guid) Returns one Entity object. If the entity is not available locally, the SDK can query the Directory for it.
Engine.GetEntity(guid, false) Returns one Entity object only if the entity is already available locally.
Engine.GetEntities(entityType) Returns Entity objects for entities of that type that are already known locally. It does not run a discovery query for missing entities.

How EntityConfigurationQuery loads data

EntityConfigurationQuery discovers and loads entity configuration data. The following example filters for cardholders and configures pagination.

var query = (EntityConfigurationQuery)
    engine.ReportManager.CreateReportQuery(
        ReportType.EntityConfiguration);

query.EntityTypeFilter.Add(EntityType.Cardholder);
query.Page = 1;
query.PageSize = 500;

var result = await Task.Factory.FromAsync(
    query.BeginQuery,
    query.EndQuery,
    null);

After this query completes, the result contains the matching cardholder GUIDs. The Engine also has the matched cardholder data available locally.

When you need the Cardholder objects, call GetEntities or GetEntity.

var cardholders = engine
    .GetEntities(EntityType.Cardholder)
    .OfType<Cardholder>();

Use GuidsOnly for discovery

Set GuidsOnly = true when you need identifiers but do not want to load entity data.

var query = (EntityConfigurationQuery)
    engine.ReportManager.CreateReportQuery(
        ReportType.EntityConfiguration);

query.EntityTypeFilter.Add(EntityType.Camera);
query.GuidsOnly = true;

var result = await Task.Factory.FromAsync(
    query.BeginQuery,
    query.EndQuery,
    null);

Use this pattern when you want to count, compare, batch, or select entities before deciding which entities to load.

Note

GuidsOnly = true prevents the query from loading matched entity data. DownloadAllRelatedData and StrictResults do not add observable value to a GUID-only query.

Use EntityGuids for a known candidate set

Use EntityGuids when you already have a list of candidate GUIDs and want to load or filter only those entities.

async Task<QueryCompletedEventArgs> QueryCandidatesAsync(
    Engine engine,
    IEnumerable<Guid> candidateGuids)
{
    var query = (EntityConfigurationQuery)
        engine.ReportManager.CreateReportQuery(
            ReportType.EntityConfiguration);

    foreach (Guid guid in candidateGuids)
    {
        query.EntityGuids.Add(guid);
    }

    return await Task.Factory.FromAsync(
        query.BeginQuery,
        query.EndQuery,
        null);
}

If the list is large, split the GUIDs into batches to limit the work performed by each query.

Use EntityGuids and EntityTypeFilter together

Use EntityGuids and EntityTypeFilter together to search a candidate GUID set and return only entities of the requested type.

This is useful when you have a mixed collection of entity GUIDs, such as Partition.Members, and you need one entity type from that collection.

async Task<IReadOnlyList<Guid>> GetPartitionMembersOfTypeAsync(
    Engine engine,
    Guid partitionGuid,
    EntityType entityType)
{
    var partition = engine.GetEntity(partitionGuid) as Partition;
    if (partition is null)
    {
        return Array.Empty<Guid>();
    }

    var query = (EntityConfigurationQuery)
        engine.ReportManager.CreateReportQuery(
            ReportType.EntityConfiguration);

    foreach (Guid member in partition.Members)
    {
        query.EntityGuids.Add(member);
    }

    query.EntityTypeFilter.Add(entityType);
    query.GuidsOnly = true;
    query.Page = 1;
    query.PageSize = 5000;

    var matches = new List<Guid>();
    QueryCompletedEventArgs result;

    do
    {
        result = await Task.Factory.FromAsync(
            query.BeginQuery,
            query.EndQuery,
            null);

        foreach (DataRow row in result.Data.Rows)
        {
            matches.Add((Guid)row["Guid"]);
        }

        query.Page++;
    }
    while (result.Data.Rows.Count >= query.PageSize);

    return matches;
}

When a query uses EntityGuids without EntityTypeFilter, it loads the entities identified by the specified GUIDs without filtering by entity type. Adding EntityTypeFilter limits the result to candidates of that type.

Use DownloadAllRelatedData for relationships

DownloadAllRelatedData is not a filter. It controls how much relationship data the query loads for the matched entities.

With DownloadAllRelatedData = false, the query loads the matched entities and their own data. With DownloadAllRelatedData = true, the query also loads relationship data and related entities.

Use DownloadAllRelatedData = true when your code will follow relationships in bulk. For example, use it when you query cardholders and then need assigned credentials, parent cardholder groups, and access rules.

Do not use DownloadAllRelatedData = true only to find one entity type from a relationship. That pattern can load much more data than the integration needs.

Use StrictResults for result-row guarantees

StrictResults controls result rows. It does not change the query filters, and it does not reduce the related data loaded by DownloadAllRelatedData.

Use StrictResults = true when your code must rely on every result row being an entity that matched the query filters.

var query = (EntityConfigurationQuery)
    engine.ReportManager.CreateReportQuery(
        ReportType.EntityConfiguration);

query.EntityTypeFilter.Add(EntityType.Camera);
query.DownloadAllRelatedData = true;
query.StrictResults = true;

Related data can still be available locally after a strict query. StrictResults only changes the guarantee on result.Data.Rows.

Understand lazy loading

Engine.GetEntity(guid) can retrieve a single entity that is not already available locally. Repeated calls for entities that are not locally available can send repeated Directory queries.

void PrintCardholderNamesIndividually(
    Engine engine,
    IEnumerable<Guid> cardholderGuids)
{
    foreach (Guid guid in cardholderGuids)
    {
        var cardholder = engine.GetEntity(guid) as Cardholder;
        Console.WriteLine(cardholder?.FirstName);
    }
}

To avoid per-entity retrieval, load the cardholders with EntityConfigurationQuery, and then retrieve the Cardholder objects from the Engine.

async Task PrintCardholderNamesAsync(
    Engine engine,
    IReadOnlyCollection<Guid> cardholderGuids)
{
    var query = (EntityConfigurationQuery)
        engine.ReportManager.CreateReportQuery(
            ReportType.EntityConfiguration);

    query.EntityTypeFilter.Add(EntityType.Cardholder);

    foreach (Guid guid in cardholderGuids)
    {
        query.EntityGuids.Add(guid);
    }

    await Task.Factory.FromAsync(
        query.BeginQuery,
        query.EndQuery,
        null);

    foreach (Guid guid in cardholderGuids)
    {
        var cardholder = engine.GetEntity(guid) as Cardholder;
        Console.WriteLine(cardholder?.FirstName);
    }
}

Reading a property that was not loaded by the query can still cause the SDK to fetch missing data on demand. Query the entity type directly when you need full type-specific data in bulk.

Choose the right pattern

Choose a pattern that loads only the entity data your code requires.

Goal Recommended pattern
Get matching GUIDs only Use EntityConfigurationQuery with GuidsOnly = true.
Load all entities of one type Use EntityConfigurationQuery with EntityTypeFilter.
Load known entities by GUID Use EntityConfigurationQuery with EntityGuids.
Filter known GUIDs by type Use EntityGuids and EntityTypeFilter together.
Find one entity type inside a partition Use Partition.Members as EntityGuids, add EntityTypeFilter, and set GuidsOnly = true if you only need GUIDs.
Read relationships in bulk Use DownloadAllRelatedData = true.
Keep result rows limited to matched entities Use StrictResults = true.
Avoid a server fallback for one entity Use Engine.GetEntity(guid, false).
Retrieve objects after loading data Use Engine.GetEntity or Engine.GetEntities.

See also

Platform SDK

Plugin SDK

Workspace SDK

Media SDK

Macro SDK

Web SDK

Synergis RIO

Media Gateway

Genetec Web Player

Clone this wiki locally