Repository navigation
platform sdk entity loading cache and query behavior
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.
Entity loading involves three distinct concepts. Each answers a different question.
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.
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.
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.
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. |
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>();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 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 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.
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.
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.
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 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. |
- Understanding DownloadAllRelatedData and StrictResults: Relationship loading and result-row behavior for configuration queries.
-
About the Engine entity cache: Behavior and lifecycle of cached
Entityobjects. - Detecting entity changes: Loading and subscription requirements for change notifications.
- About the ReportManager: Running report queries from the Platform SDK.
- ReportManager query reference: Query types, filters, and result schemas.
- Overview
- Connecting to Security Center
- SDK certificates
- Referencing SDK assemblies
- ASP.NET hosting
- SDK compatibility
- Migrating to modern .NET
- Entities
- Entity cache
- Entity loading, cache, and query options
- Detecting entity changes
- Entity change event reference
- Transactions
- Security Center events
- Actions
- Security Desk
- Custom events
- Event-to-actions
- Managing macros
- ReportManager
- ReportManager query reference
- Access control raw events
- DownloadAllRelatedData and StrictResults
- Privileges
- Partitions
- Entity write restrictions
- About custom fields
- About video
- About cameras
- Enrolling a video unit
- Ingesting third-party video
- Archiver and auxiliary archiver roles
- Archive transfer
- About access control
- About cardholders and credentials
- About doors, areas, elevators, and access points
- About access rules and schedules
- About access control units and interface modules
- Enrolling an access control unit
- Door templates
- Visitors
- Mobile credentials
- About threat levels
- About alarms
- About incidents
- Maps
- Logging
- Overview
- Localization
- Certificates
- Lifecycle
- Threading
- State management
- Configuration
- Restricted configuration
- Events
- Queries
- Request manager
- Database
- Entity ownership
- Engine extensions
- Entity mappings
- Server management
- Custom privileges
- Custom entity types
- Resolving non-SDK assemblies
- Deploying plugins
- Modern .NET support
- Overview
- Localization
- Certificates
- Creating modules
- Tasks
- Pages
- Components
- Tile extensions
- Services
- Contextual actions
- Custom actions
- Options extensions
- Configuration pages
- Monitors
- Shared components
- Commands
- Extending events
- Map extensions
- Timeline providers
- Image extractors
- Credential encoders
- Credential readers
- Cardholder fields extractors
- Badge printers
- Content builders
- Dashboard widgets
- Incidents
- Logon providers
- Pinnable content builders
- Custom report pages
- Overview
- Getting started
- Media file formats
- MediaPlayer
- VideoSourceFilter
- MediaExporter
- MediaFile
- G64 converters
- FileCryptingManager
- PlaybackSequenceQuerier
- PlaybackStreamReader
- OverlayFactory
- PtzCoordinatesManager
- AudioTransmitter
- AudioRecorder
- AnalogMonitorController
- Camera blocking
- Overview
- Getting started
- Referencing entities
- Entity operations
- About access control in the Web SDK
- About video in the Web SDK
- Users and user groups
- Partitions
- Custom fields
- Custom card formats
- Actions
- Events and alarms
- Incidents
- Reports
- Tasks
- Macros
- Custom entity types
- System endpoints
- Performance guide
- Reference
- Endpoints
- Constants
- Enumerations
- Under the hood
- Troubleshooting