LoadEntitiesCommand
Overviewβ
The LoadEntitiesCommand is a secure, enterprise-grade data query command that allows you to load and filter data from approved entities (database tables) within your BankLingo workflows. This command provides flexible querying capabilities while maintaining strict security controls to prevent SQL injection attacks and unauthorized access to sensitive data.
This command implements multiple layers of security validation including:
- β Whitelisted entities only - Only pre-approved tables can be queried
- β Sensitive field blocking - Password, PINs, and security keys are automatically filtered
- β SQL injection protection - Dangerous SQL keywords are blocked
- β Input validation - All parameters are validated before query execution
When to Use This Commandβ
β Good Use Cases:β
- Workflow data loading: Load customer, branch, or transaction data during process execution
- Dynamic lookups: Fetch related entities based on workflow context
- List population: Get dropdown options or reference data for user tasks
- Data validation: Check if records exist before performing operations
- Filtered queries: Retrieve specific records based on business logic
β Bad Use Cases:β
- Complex reporting (use dedicated reporting tools instead)
- Data modifications (use specific update commands instead)
- Joining multiple tables (design specific commands for complex queries)
- Retrieving sensitive authentication data (automatically blocked)
Available Entities (Whitelist)β
Only the following entities are available for querying. Attempting to query unlisted entities will result in an error.
π See the complete field reference guide with all available fields, data types, and examples:
ββ LoadEntitiesCommand Field Reference
Self-Service Entities (18)β
| Entity Name | Description |
|---|---|
UserRepo | Self-service users |
TransactionRepo | User transactions |
BankRepo | Bank information |
BranchRepo | Branch information |
AreaRepo | Geographic areas |
DivisionRepo | Organizational divisions |
OrganisationRepo | Organizations |
PlanTypeRepo | Plan types |
UserBeneficiaryRepo | User beneficiaries |
LoanQuoteRepo | Loan quotes/applications |
UserDetailRepo | User personal details (names, etc.) |
GuaratorInformationRepo | Guarantor information |
NextOfKinInformationRepo | Next of kin details |
EmploymentInformationRepo | Employment records |
SelfServiceIdentityInformationRepo | Identity documents |
SelfServiceAddressInformationRepo | Address records |
SelfServiceDisbursementInformationRepo | Disbursement details |
SelfServiceLoanCollectionInformationRepo | Collection account info |
Core Banking Entities (11)β
| Entity Name | Description |
|---|---|
ClientRepo | Bank clients/customers |
LoanAccountRepo | Loan accounts |
DepositAccountRepo | Deposit accounts |
DepositTransactionRepo | Deposit transactions |
LoanTransactionRepo | Loan transactions |
CBSTransactionRepo | Core banking transactions |
BranchCoreRepo | Core banking branches |
DepositProductRepo | Deposit product definitions |
LoanProductRepo | Loan product definitions |
JournalEntryRepo | Journal entries |
GLAccountRepo | General Ledger accounts |
Total Entities: 29 (18 Self-Service + 11 Core Banking)
β¨ 9 New Self-Service Entities Added: LoanQuote, UserDetail, Guarantor Information, Next of Kin, Employment Information, Identity Information, Address Information, Disbursement Information, and Collection Information - now available for querying loan application data!
To add a new entity, contact your system administrator. Entities must be explicitly whitelisted in RepoTableMapping for security reasons.
Blocked Sensitive Fieldsβ
The following fields are automatically blocked and cannot be queried, even if explicitly requested. This protects sensitive user data from unauthorized access.
π Password & Authenticationβ
Password,PasswordHash,PasswordSalt,HashedPassword,UserPassword
π Two-Factor Authenticationβ
TwoFASecretKey,TwoFASecret,AuthenticatorSecret,Authentication2FARequestId,OTPSecret
π Security Questions & Answersβ
SecurityAnswer1,SecurityAnswer2,SecurityAnswer3SecurityQuestion1,SecurityQuestion2,SecurityQuestion3
π API Keys & Tokensβ
ApiKey,ApiSecret,AccessToken,RefreshToken,BearerToken,SecretKey,PrivateKey
π PINs & Biometricsβ
PIN,TransactionPIN,ATMPin,CardPINFingerprint,FingerprintData,BiometricData,FaceData
π Financial Secretsβ
CVV,CardCVV,CardSecurityCode,AccountPIN
π Session & Encryptionβ
SessionSecret,SessionKey,EncryptionKey
π Personal IDsβ
SSN,SocialSecurityNumber,TaxId,NationalId
If you request blocked fields:
- Single field: The field is silently excluded from results
- Multiple fields: Other safe fields are returned, blocked fields are filtered
- All blocked fields: Request fails with HTTP 403 Forbidden
Parametersβ
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
entity | string | β Yes | - | The entity (repository) name to query. Must be from the whitelist. |
fields | string | No | "*" | Comma-separated list of fields to return. Use "*" for all fields (sensitive fields still excluded). When using JOINs, use full repo names (e.g., LoanQuoteRepo.Id, UserRepo.EmailAddress). |
filter | string | No | null | SQL WHERE clause (without "WHERE" keyword). Must not contain dangerous SQL keywords. Use full repo names in filter expressions (e.g., LoanQuoteRepo.ApprovalState = 1). |
order | array<string> | No | [] | Array of field names to sort by (ascending order). |
page | number | No | null | Page number for pagination (1-based). Requires size parameter. |
size | number | No | null | Number of records per page. Maximum: 1000. Requires page parameter. |
When referencing fields (especially with JOINs), always use the full repository name as documented:
- β
Correct:
LoanQuoteRepo.Id, UserRepo.EmailAddress, ClientRepo.FirstName - β Wrong: Using any shortened notation or alternative formats
Always match the repository names exactly as they appear in the entity list above. The system handles all internal processing securely.
Response Formatβ
Success Responseβ
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 25,
"Size": 10,
"Pages": 3,
"Data": [
{
"Id": 1,
"UserId": "user@example.com",
"EmailAddress": "user@example.com",
"UserStatus": 1,
"DefaultBranchId": 5
},
// ... more records
]
}
Error Responseβ
{
"IsSuccessful": false,
"Message": "Entity 'InvalidRepo' is not available for querying. Please use one of the allowed entities.",
"StatusCode": "400"
}
Response Fieldsβ
| Field | Type | Description |
|---|---|---|
IsSuccessful | boolean | true if query succeeded, false otherwise |
Message | string | Success message or error description |
StatusCode | string | HTTP status code: "200" (success), "400" (bad request), "403" (forbidden), "500" (server error) |
Count | number | Number of records returned in current page |
Size | number | Requested page size |
Pages | number | Total number of pages (if pagination is used) |
Data | array | Array of records (each record is an object with field-value pairs) |
Examplesβ
Example 1: Load All Users (Basic Query)β
Use Case: Get all self-service users for a dropdown list.
Request:
{
"entity": "UserRepo"
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 150,
"Size": 0,
"Pages": 1,
"Data": [
{
"Id": 1,
"UserId": "john.doe@example.com",
"EmailAddress": "john.doe@example.com",
"UserStatus": 1,
"DefaultBranchId": 3,
"UserClassification": 1,
"AccountType": 2
},
// ... more users
]
}
Example 2: Load Specific Fields Onlyβ
Use Case: Get only user ID and email for performance reasons.
Request:
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress"
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 150,
"Data": [
{
"Id": 1,
"UserId": "john.doe@example.com",
"EmailAddress": "john.doe@example.com"
},
{
"Id": 2,
"UserId": "jane.smith@example.com",
"EmailAddress": "jane.smith@example.com"
}
]
}
Example 3: Filter Users by Statusβ
Use Case: Get only active users (UserStatus = 1).
Request:
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress, UserStatus",
"filter": "UserStatus = 1"
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 120,
"Data": [
{
"Id": 1,
"UserId": "john.doe@example.com",
"EmailAddress": "john.doe@example.com",
"UserStatus": 1
},
// ... only active users
]
}
Example 4: Filter with Multiple Conditionsβ
Use Case: Get active profile admins from a specific branch.
Request:
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress, IsProfileAdmin, DefaultBranchId",
"filter": "UserStatus = 1 AND IsProfileAdmin = 1 AND DefaultBranchId = 5"
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 3,
"Data": [
{
"Id": 15,
"UserId": "admin1@example.com",
"EmailAddress": "admin1@example.com",
"IsProfileAdmin": true,
"DefaultBranchId": 5
},
{
"Id": 28,
"UserId": "admin2@example.com",
"EmailAddress": "admin2@example.com",
"IsProfileAdmin": true,
"DefaultBranchId": 5
}
]
}
Example 5: Sort Resultsβ
Use Case: Get users sorted by email address.
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress",
"order": ["EmailAddress"]
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 150,
"Data": [
{
"Id": 45,
"UserId": "alice@example.com",
"EmailAddress": "alice@example.com"
},
{
"Id": 12,
"UserId": "bob@example.com",
"EmailAddress": "bob@example.com"
},
// ... sorted alphabetically
]
}
Example 6: Pagination (Page 1)β
Use Case: Get the first 10 users from a large dataset.
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress",
"page": 1,
"size": 10
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 10,
"Size": 10,
"Pages": 15,
"Data": [
{
"Id": 1,
"UserId": "user1@example.com",
"EmailAddress": "user1@example.com"
},
// ... 10 records total
]
}
Example 7: Pagination (Page 2)β
Use Case: Get the next 10 users.
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress",
"page": 2,
"size": 10
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 10,
"Size": 10,
"Pages": 15,
"Data": [
{
"Id": 11,
"UserId": "user11@example.com",
"EmailAddress": "user11@example.com"
},
// ... next 10 records
]
}
Example 8: Load Branches for Dropdownβ
Use Case: Get all branches with ID and name for a selection dropdown.
{
"entity": "BranchRepo",
"fields": "Id, BranchName, BranchCode",
"filter": "IsActive = 1",
"order": ["BranchName"]
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 25,
"Data": [
{
"Id": 1,
"BranchName": "Head Office",
"BranchCode": "HQ001"
},
{
"Id": 5,
"BranchName": "Downtown Branch",
"BranchCode": "DTN002"
}
]
}
Example 9: Check if User Existsβ
Use Case: Validate that a user with a specific email exists before creating a transaction.
{
"entity": "UserRepo",
"fields": "Id, UserId",
"filter": "EmailAddress = 'john.doe@example.com'"
}
Response (User Found):
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 1,
"Data": [
{
"Id": 15,
"UserId": "john.doe@example.com"
}
]
}
Response (User Not Found):
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 0,
"Data": []
}
Example 10: Filter with IN Clauseβ
Use Case: Get users from specific branches only.
{
"entity": "UserRepo",
"fields": "Id, UserId, DefaultBranchId",
"filter": "DefaultBranchId IN (1, 3, 5)"
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully.",
"StatusCode": "200",
"Count": 45,
"Data": [
{
"Id": 1,
"UserId": "user1@example.com",
"DefaultBranchId": 1
},
{
"Id": 5,
"UserId": "user5@example.com",
"DefaultBranchId": 3
}
]
}
Security Examplesβ
Example 11: β Attempting to Query Password (Blocked)β
Request:
{
"entity": "UserRepo",
"fields": "Id, UserId, Password"
}
Response:
{
"IsSuccessful": false,
"Message": "All requested fields are blocked for security reasons: Password",
"StatusCode": "403"
}
Example 12: Γ’Ε‘Β Γ―ΒΈΒ Requesting Sensitive + Safe Fieldsβ
Request:
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress, Password, TwoFASecretKey"
}
Response:
{
"IsSuccessful": true,
"Message": "Data loaded successfully. Note: 2 sensitive field(s) were excluded from results for security reasons.",
"StatusCode": "200",
"Count": 150,
"Data": [
{
"Id": 1,
"UserId": "john.doe@example.com",
"EmailAddress": "john.doe@example.com"
// Password and TwoFASecretKey are excluded
}
]
}
Example 13: β SQL Injection Attempt (Blocked)β
Request:
{
"entity": "UserRepo",
"filter": "Id = 1 OR 1=1; DROP TABLE Users--"
}
Response:
{
"IsSuccessful": false,
"Message": "Filter contains invalid SQL keywords. Please review your filter expression.",
"StatusCode": "400"
}
Example 14: β Attempting to Query Unmapped Entity (Blocked)β
Request:
{
"entity": "PasswordHistoryRepo"
}
Response:
{
"IsSuccessful": false,
"Message": "Entity 'PasswordHistoryRepo' is not available for querying. Please use one of the allowed entities.",
"StatusCode": "400"
}
Example 15: β Invalid Filter Characters (Blocked)β
Request:
{
"entity": "UserRepo",
"filter": "Id = 1 -- Comment out rest"
}
Response:
{
"IsSuccessful": false,
"Message": "Filter contains invalid characters (comments or multiple statements).",
"StatusCode": "400"
}
Integration in Workflowsβ
Use in Service Taskβ
{
"taskType": "serviceTask",
"taskId": "loadActiveUsers",
"taskName": "Load Active Users",
"commandType": "App.Commands.BPM.Entities.LoadEntitiesCommand",
"parameters": {
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress, DefaultBranchId",
"filter": "UserStatus = 1 AND IsProfileAdmin = 1",
"order": ["EmailAddress"]
}
}
Use Variable Substitution in Filterβ
{
"taskType": "serviceTask",
"taskId": "loadUserByEmail",
"taskName": "Load User By Email",
"commandType": "App.Commands.BPM.Entities.LoadEntitiesCommand",
"parameters": {
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress",
"filter": "EmailAddress = '{{userEmail}}'"
}
}
Store Results in Workflow Contextβ
After execution, access the loaded data in subsequent tasks:
// Check if users were found
if (context.loadActiveUsers.Count > 0) {
// Get first user
var firstUser = context.loadActiveUsers.Data[0];
var userId = firstUser.Id;
var email = firstUser.EmailAddress;
}
Filter Expression Guidelinesβ
β Allowed Operations:β
- Comparison:
=,!=,<>,<,>,<=,>= - Logical:
AND,OR,NOT - Patterns:
LIKE '%value%' - Ranges:
BETWEEN x AND y - Lists:
IN (1, 2, 3) - Null checks:
IS NULL,IS NOT NULL
β Blocked Operations:β
- Data modification:
DROP,DELETE,INSERT,UPDATE,TRUNCATE,ALTER,CREATE - Execution:
EXEC,EXECUTE,sp_*,xp_* - Joins:
UNION,MERGE - Permissions:
GRANT,REVOKE - Comments:
--,/*,*/ - Multiple statements:
;
Γ°ΕΈβΒ Filter Best Practices:β
-
Use single quotes for strings:
filter: "EmailAddress = 'user@example.com'" -
Combine multiple conditions:
filter: "UserStatus = 1 AND DefaultBranchId IN (1, 3, 5)" -
Use wildcards for partial matches:
filter: "EmailAddress LIKE '%@example.com'" -
Check for NULL values:
filter: "CorporateProfileId IS NOT NULL" -
Escape single quotes in values:
filter: "UserName = 'O''Brien'"
Performance Considerationsβ
π Optimization Tips:β
-
Request only needed fields:
- β
"fields": "Id, UserId, EmailAddress" - β
"fields": "*"(returns all columns)
- β
-
Use filters to reduce result set:
- Add WHERE conditions to limit records returned
- Filter at database level, not in application code
-
Use pagination for large datasets:
- Set reasonable
size(e.g., 10-50 records per page) - Maximum page size is capped at 1000 records
- Set reasonable
-
Sort only when necessary:
- Sorting adds processing overhead
- Sort in application if already dealing with small datasets
-
Index your filter fields:
- Ensure database columns used in
filterare indexed - Contact DBA for index optimization
- Ensure database columns used in
Error Handlingβ
Common Error Codesβ
| Status Code | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid entity name, malformed filter, invalid pagination parameters |
403 | Forbidden | Attempting to access blocked sensitive fields |
500 | Internal Server Error | Database connection issues, malformed SQL, system errors |
Error Response Examplesβ
Invalid Entity:
{
"IsSuccessful": false,
"Message": "Entity 'InvalidRepo' is not available for querying. Please use one of the allowed entities.",
"StatusCode": "400"
}
Invalid Page Size:
{
"IsSuccessful": false,
"Message": "Page size must be greater than 0.",
"StatusCode": "400"
}
Dangerous SQL Keywords:
{
"IsSuccessful": false,
"Message": "Filter contains invalid SQL keywords. Please review your filter expression.",
"StatusCode": "400"
}
Security Architectureβ
Threat Protectionβ
| Threat | Protection Mechanism |
|---|---|
| SQL Injection | Keyword blacklist, character validation, no dynamic table names |
| Data Breach | Sensitive field filtering, whitelisted entities only |
| DoS Attack | Pagination limits (max 1000 records), query timeout |
| Privilege Escalation | Entity whitelist prevents access to unauthorized tables |
| Information Disclosure | Post-query sanitization removes sensitive fields from results |
Logging & Auditingβ
The command logs the following events:
| Event | Log Level | Information Logged |
|---|---|---|
| Command invocation | Information | Entity name |
| Query execution | Information | Generated SQL query |
| Successful query | Information | Record count |
| Blocked field access | Warning | Requested field name |
| SQL injection attempt | Warning | Dangerous filter content |
| Invalid entity | Warning | Requested entity name |
| Errors | Error | Exception details |
Best Practicesβ
β DO:β
- Explicitly list required fields instead of using
* - Use pagination for large datasets
- Add filters to reduce result size
- Validate returned
Countbefore processingData - Handle empty result sets gracefully (
Count = 0) - Use workflow variables in filters for dynamic queries
β DON'T:β
- Request sensitive fields (automatically blocked anyway)
- Build complex multi-table joins (use dedicated commands)
- Use wildcards (
*) in production workflows - Construct SQL injection patterns (will be rejected)
- Query unmapped entities (not in whitelist)
- Assume data exists without checking
Count
Migration from Legacy Queriesβ
If you're migrating from direct SQL queries to LoadEntitiesCommand:
Before (Insecure):β
Implementation details removed for security.
Contact support for implementation guidance.
After (Secure):β
{
"entity": "UserRepo",
"fields": "Id, UserId, EmailAddress",
"filter": "EmailAddress = '{{userInput}}'"
}
Troubleshootingβ
Issue: "Entity not available for querying"β
Solution: Check that you're using the correct entity name from the whitelist. Entity names are case-insensitive but must match exactly.
Issue: "All requested fields are blocked"β
Solution: You requested only sensitive fields. Request non-sensitive fields like Id, UserId, EmailAddress instead.
Issue: "Filter contains invalid SQL keywords"β
Solution: Remove keywords like DROP, DELETE, EXEC from your filter. Use only comparison and logical operators.
Issue: "Invalid field name format"β
Solution: Field names can only contain alphanumeric characters, dots, underscores, and brackets. Remove special characters.
Issue: Results return fewer fields than expectedβ
Solution: Some requested fields may have been blocked for security. Check the response Message for warnings about excluded fields.
Related Commandsβ
- DoSqlQuery: For more complex queries with joins (use with caution)
- GetFullTableQuery: Alternative querying mechanism
- Service-specific commands: For entity-specific operations (CreateUser, UpdateBranch, etc.)
Support & Contactβ
For questions about:
- Adding new entities to whitelist: Contact your system administrator
- Performance issues: Contact your database administrator
- Security concerns: Contact your security team
- Integration help: Refer to Process Engine documentation
Changelogβ
| Version | Date | Changes |
|---|---|---|
| 2.0 | 2024-12-26 | Added comprehensive security validation, field blocking, SQL injection protection |
| 1.0 | 2024-01-01 | Initial release with basic query functionality |
Last Updated: December 26, 2024
Command Path: App.Commands.BPM.Entities.LoadEntitiesCommand
Handler: LoadEntitiesCommandHandler