HTML |
---|
<style>
.text-span-6 {
background-image: linear-gradient(99deg, rgba(170, 163, 239, .5), rgba(125, 203, 207, .5));
border-radius: 50px;
padding-left: 15px;
padding-right: 15px;
}
#title-text {
display: none;
}
.panelgradient {
background-image: linear-gradient(180deg, #d5def0, whitesmoke);
border-radius: 8px;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 4rem;
display: flex;
position: relative;
}
</style>
<div class ="panelgradient">
<h1 style="text-align: center;">Datasets <br> (Databases and SQL Queries)</h1>
</div> |
Introduction to the Datasets Module
The Datasets Module is designed for data exchange with SQL databases and text files from a diverse set of sources. Essentially, the Datasets Module drives bi-directional real-time communication between all modules and the SQL databases.
This module offers compatibility with various database technologies, including ADO.NET, ODBC, OleDB, and native interfaces, providing straightforward configuration with prominent databases such as SQL Server, Oracle, SQLite, and PostgreSQL. Features include:
- Multi-threaded concurrent connections with multiple databases for efficient data handling
- SQL Query editor, SQLite admin tool, and a Visual Query Builder, streamlining the configuration experience
- Customization of SQL statements in real-time with tags and system events
On this page:
Table of Contents | ||||||
---|---|---|---|---|---|---|
|
Key Concepts and Terms
DatasetDB
Connections settings created by the Dataset Module to communicate with an external database.
DatasetQuery
Logical name associated with the configuration for SQL query statements with a Database, and its properties and methods for running queries.
DatasetTable
Logical name created to hold configuration settings to access specific tables in a connected database, mapping tags to table columns for operations.
DatasetFile
Logical name defining parameters for reading and writing files in ASCII, Unicode, or XML formats.
Understanding the Datasets Module
The Datasets Module enables users to interact with SQL databases seamlessly. The module supports real-time Tags within SQL statements, and manages files and recipes in ASCII, Unicode, or XML formats.
Introduction to Datasets module
The Dataset Module is designed for data exchange with SQL databases and text files from a diverse set of sources. This module offers compatibility with a wide array of database technologies, including ADO.NET, ODBC, OleDB, and native interfaces, providing straightforward configuration with prominent databases such as SQL Server, Oracle, SQLite, and PostgreSQL.
Features include multi-threaded concurrent connections for efficient data handling, a dedicated SQLite editor for streamlined database management, and an intuitive visual query builder that simplifies the process of query creation and manipulation. Moreover, the Dataset module is equipped to integrate real-time tags within query strings, enhancing the dynamism of data interaction. It can also manage files and recipes in ASCII, Unicode, or XML formats, broadening its applicability across different data types.
On this page:
Table of Contents | ||||
---|---|---|---|---|
|
Purpose and Key Concepts
The purpose of the Dataset module in FrameworX is to facilitate efficient data exchange between the platform and various external databases and text files, thereby creating a robust data infrastructure that empowers other real-time modules to function effectively.
Dataset DBs
In order for the Dataset module to communicate with an external database, a connection must be created with certain parameters. These connections, which are created within the Datasets → DBs section of the module, are referred to as Dataset DBs.
Dataset Queries
In the context of the Dataset module, a Dataset Query refers not only to an SQL query string, but also to a Project object that has a logical name, an SQL query related to that logical name, and other parameters defined within the Datasets → Queries section. There are many ways to automatically map the results of a query execution with Tags.
Dataset Tables
A Dataset Table is a logical name that is created within a project to set up access to a specific table in a connected database. These tables are listed within the Datasets → Tables section of the module. The Tags in the real-time database can easily be mapped to columns in the tables to perform insert, update, or read operations.
Dataset Files
A Dataset File is a logical name that defines parameters for reading and writing files in ASCII, Unicode, or XML formats. To manage the Dataset Files go to Datasets → Files.
Using Tags in the Dataset module
In the Dataset module, you can utilize Tags from your project as dynamic placeholders within SQL queries or file names. This capability facilitates real-time data manipulation within the query strings. Moreover, you can map the results of the queries to Tags, or employ Tags to populate values when inserting or modifying existing records.
Understanding the Datasets module
Overview
The Datast modules allows easy ashes to SQL database bases, so you exchange values for Tables and query its twitch tags in the a[p[plica,
Data UtilizationThe data retrieved from databases can be utilized in various ways throughout your projectyour solution. For example:
- In the Displays Module: Visualization tools like DataGrids can present query results on screens and dashboards, creating custom views of the data that are accessible and easy to understand for your users.
- In the Scripting Module: Custom scripts can reference query results and trigger specific actions, such as sending notifications, updating tags, or performing calculations, thereby implementing complex logic based on database
In a similar fashion, various modules can add data to your SQL databases. For instance, the Displays Module can log operations inputs and commands, the Scripting Module can calculate analytics, and the Alarm and Historian Module can retain long-term records and audit trails. Essentially, the Dataset module drives bi-directional real-time communication between all Project Modules and the SQL databases.
Processing Data Requests
- Datasets Data Server Service
The Datasets Data Server Service forms an integral part of the Datasets module, ensuring high performance and seamless integration while exchanging structured collections of data in real-time. It efficiently processes data requests from other modules, enabling connectivity with various components such as HMI/SCADA screens, scripting, and reporting tools.
- Default Databases Used when Running the Project
The Dataset module also serves as a data storage configuration hub for other modules. The Alarm and Historian modules, which generate events and records for long-term retention, utilize the Dataset module for defining data storage. Similarly, the Security Module can utilize user definitions from an external database defined within the Dataset module.
Data Source Virtualization
Data Source Virtualization is an advanced feature that simplifies data management across multiple data sources. It provides a unified interface for accessing, querying, and manipulating data, regardless of the underlying data storage technology. This feature allows modifications to the underlying data sources repositories without impacting the rest of the application.
- Agnostic, Standards, Centralized Management
Adhering to industry standards, the module is designed to work seamlessly with various data storage technologies. It enables centralized management of data connections and configurations, streamlining the process of integrating different data sources into your projects.
For a more detailed explanation of how the Dataset module works, please refer to the page Advanced Dataset Guide.
Configuring the Dataset module
Configuration Workflow
The typical configuration workflow for the Dataset module has the following sequence:Establish Database Connections:
- Navigate to Datasets → DBs to create essential database connections.
- Gather connection details for project databases.
- Leverage the built-in SQLite database for temporary development purposes.
Prepare Queries:
- Access Datasets → Queries to craft queries using the Visual Query Editor or provided SQL strings.
- Assign logical names (Dataset.Query) to identify and streamline query usage.
- Implement a virtualization model for seamless transition to the production database.
Modify Queries for Real-time Interaction:
- Fine-tune queries at Datasets → Queries by adding real-time parameters.
- Example: Transform "WHERE col1 = 5" to "WHERE col1 = {{tag.Test}}".
Manage Project Tables:
- Navigate to Datasets → Tables for direct management of database tables.
- Connect inserted data with project Tags for efficient data handling.
- Utilize tables directly when all necessary information resides in a single table.
Configure Stored Procedures:
- Extend functionality at Datasets → Queries by configuring and executing Stored Procedures.
- Utilize the same interface for defining Stored Procedures as for queries.
Exchange Data with Files:
- Establish file-based data exchange configurations at Datasets → Files.
- Configure interactions with plain text or XML files as needed.
Utilize Logical Objects:
- Leverage logically named objects (Queries, Tables, Files) throughout the project.
- Examples: Apply in script calculations, visualization displays, and other project components.
When using SQLite databases, the Module Dataset can automatically create the Database localy if they don't already exist; for other database types, the database itslef must already exist before you set your connection.
Info |
---|
Users with any Permission groups can create new connections in the Project, but only the Administrator can configure databases password logins. |
There are four database connection already created in any new Project:
Datasets DB - Pre-defined database connections
DB
Database
Path Location
Usage
Retentive
SQLite
<ProjectNameAndPath>.dbRetentive
Stores values for Retentive Tags.
RuntimeUsers
SQLite
<ProjectNameAndPath>.dbRuntimeUsers
Stores dynamically created Users.
AlarmHistorian
SQLite
<ProjectNameAndPath>.dbAlarmHistorian
Stores Alarm and AuditTrail records.
TagHistorian
SQLite
<ProjectNameAndPath>.dbTagHistorian
Stores Tag Historian and Annotations.
Any of them can be customized to any type of database.
The selection of best storage location depends on all kind of factors, from internal company procedures to the volume of data and how the data shall be used. Therefore, that is decision to each Project according to its requirements.
If needed to use another database for the pre-defined connections, execute the following steps:
Rename or Delete the previous DB. This step is necessary, as the system would not allow to create two objects with the same name.
- Crate a new DB with the same name of the previous DB, with the required Database and connection strings.
Check the Dataset DBs guide for comprehensive details.
Users can enhance data manipulation by configuring queries with SQL statements in the Dataset module. The Visual Query Editor simplifies the process, allowing users to drag and drop tables, define relationships, and apply filters through an intuitive graphical interface. Created queries can be saved and executed seamlessly within the module.
Check the Visual SQL Query Builder page for complete information.
Check the Dataset Queries guide for comprehensive details.
Effortlessly manage data tables within the Dataset module. Configure table properties such as structure, relationships, and data types. The intuitive interface streamlines customization, ensuring efficient data handling.
Check the Dataset Tables guide for comprehensive details.
Customize file interactions in the Dataset module with ease. Configure file-related properties, define formats, and establish connections. The module provides a user-friendly interface for managing various file types seamlessly.
Check the Dataset Files guide for detailed configuration instructions.
Working with the Dataset module
Runtime Execution
One of the key features of the Dataset module is the ability to execute SQL queries and retrieve data in real-time. Here are some ways to leverage the runtime execution features of the Dataset Module:
- Create SQL queries to retrieve data from external databases.
- Use query results to trigger events and actions within the platform environment.
- Configure event triggers based on specific query criteria, such as changes to a specific data point or a threshold value being exceeded.
The Dataset module can be easily integrated with other modules within the software environment. Here are some examples of how the Dataset module can be used in conjunction with other modules:
- Alarm Manager: Configure alarms based on query results to trigger notifications and actions.
- Visualization: Display query results on screens and dashboards using DataGrids and other visualization tools.
- Scripting: Use query results to trigger custom scripts and perform complex data processing and analysis.
By leveraging these integration options, users can gain greater insight and control over their data sources within the platform. With the ability to execute SQL queries and trigger actions based on query results, the Dataset module provides a powerful set of tools for working with data.
- data.
- Devices: Sending data from field equipments to a SQL database, or applying settings from the database to the field equipments.
Pre-defined Database Connections
The Dataset Module also serves as a data storage configuration hub for other modules. The following Database connections are pre-defined by the Dataset Module.
- AlarmHistorian: Events and records for long-term retention.
- TagHistorian: Time-series storage for process variables,
- RuntimeUsers: Dynamics users and credentials created when running the solution.
- Retentive: Persistent records for tags and properties that need to be kept across multiple starts of the solution (typically configuration settings and setpoints).
Processing Data Requests
The Datasets Module has its implementation running as a service, which ensures high performance and real-time responses to multiple client requests.
This architecture also enhances protection and security for the database, as client displays and scripts won't access the databases directly, but through the Datasets Service.
Another benefit is the ability for Data Source Virtualization, meaning that when the solution is using Dataset.Query.Query1
in its displays or scripts, the database running that query, along with the query itself, can be maintained or replaced without affecting the overall solution configuration. This feature allows the solution to work with the data, regardless of the underlying data storage technology.
For an advanced deeper understanding of the Datasets Services, see Dataset Advanced Topics.
Configuring the Datasets Module
Configuration Workflow
The typical configuration workflow for the Dataset module has the following sequence:
Datasets Module Configuration Workflow | ||
---|---|---|
Action | Where | Comments |
Define database connections | Datasets / DBs | Gather connection details for your applications databases and created DB objects as need. Leverage the built-in SQLite admin tool for temporary development purposes |
Prepare Queries | Datasets / Queries DataExplorer / SQL VisualQueryBuilder | To craft queries using the built-in SQL Language Editor, the VisualQueryBuilder or using provided SQL statements from other sources. Fine-tune queries adding real-time parameters. Eg.: Transform "WHERE col1 = 5" to "WHERE col1 = {{tag.Test}}". |
Map Database Tables | Datasets / Tables | Optionally, you can establish a direct mapping to tables within the Database. |
Map Recipes and Text files | Datasets / Files | Optionally, your solution may need to save or load recipes, or other information, from ASCII, Unicode, or XML files. |
Managing DB Connections
There are four database connections pre-defined in any new solution.
Datasets DB - Pre-defined database connections | |||
---|---|---|---|
DB | Database | Path Location | Usage |
Retentive | SQLite | <ProjectNameAndPath>.dbRetentive | Stores values for the Tags with the Retentive property set. |
RuntimeUsers | SQLite | <ProjectNameAndPath>.dbRuntimeUsers | Stores dynamically created Solution SecurityUsers. |
AlarmHistorian | SQLite | <ProjectNameAndPath>.dbAlarmHistorian | Stores Alarm and AuditTrail records. |
TagHistorian | SQLite | <ProjectNameAndPath>.dbTagHistorian | Stores Tag Historian and Annotations. |
When using SQLite databases, the Dataset Module can automatically create the database locally if it doesn't already exist. For other database types, the database itself must already exist before you set your connection.
→ Read more about Datasets DBs.
DatasetQueries Configuration
Use the DatasetQueries to define SQL Statements, for queries and stored procedures to execute in connection of the created DatasetDB databases.
→ Read more about Datasets Queries
DatasetTables Configuration
Use the DatasetTables to access or exchange data with databases tables, with simplified query syntax. It allows allow insert new rows directly on database tables.
→ Read more about Datasets Tables.
DatasetFiles Configuration
The DatasetFiles are used to customize file interactions in the Dataset Module. With this feature you can read or write realtime tags to ASCII, Unicode and XAML files.
→ Read more about Datasets Files.
Working with the Datasets Module
Runtime Execution
When executing the solution, there is an infrastructure of services that manages access to the database and transports that information to where it is requested. For instance, to display a Dataset Query result on an HTML5 page, that request first goes to the server, which then requests the database (which can be on another computer), and the information flows back to the requester.
As database operations can take some time to execute, it is very important to understand some aspects of the Datasets Module execution, including the concept of synchronous vs. asynchronous requests.
The page Datasets Module Execution details concepts that describe the module's internal operations.
Showing DataGrids Tables on Displays
One typical use of the Dataset Module is to display query results on displays and dashboards.
In order to do so, create the DatasetQuery, or DatasetTable, then use the DataGrid Control on your displays.
Using Query Results on Scripts and Tags
It's possible to define the SQL statements with code (either using the Scripts Module or Display CodeBehind) and connect the results with tags early on.
The property Dataset.Query.QueryName.SqlStatement
holds the query that will be executed; just modify that property within your scripts.
The Tag Type DATATABLE was created to be compatible with results of Select()
statements. Simply apply the results to your query and use tags to manage the information.
The TK (Toolkit extension for Scripts) has methods that allow for easy copying between DataTables (query results) and Template Tags, like TK.CopyTagToDataTable()
.
Monitoring Databases Connection Status
Monitoring Database Connections is an essential aspect of maintaining a reliable operation of the solution.
This can be accomplished using the Dataset Namespace properties, which provide status for DatasetTables and DatasetQueries operations.
→ Read more about Datasets Runtime Attributes.
During the Development phase, when the Designer tools is connected with a Runtime (the Solution is in execution), the main status conditions can be seen in the monitoring page.
→ Read more about Datasets Monitor
Datasets Advanced Topics
Datasets Module Execution
The Dataset module facilitates efficient database interactions by utilizing TServer services, managing synchronous and asynchronous executions for optimal performance.
→ Read more about Databases Module Execution.
Data Management
The Dataset Module offers versatile methods for managing data and concurrency within solutions, including Data Table tags and Async Contents.
→ Read more about at Data Management.
Datasets Runtime Attributes
The Datasets Namespace exposes properties and methods from the .NET objects used by the Historian Module execution. You can use these properties and methods on your Displays or to create Scripts and Alarms.
→ Read more about at Datasets Runtime Attributes.
Preventing SQL Injections
Prevent SQL injections by using parameterized queries or stored procedures with proper parameter binding. Avoid concatenating user inputs directly into SQL statements. In .NET, use APIs to add parameters to commands. This ensures inputs are treated as values, not executable code.
→ Read more about at Datasets Advanced Topics.
Network Gateway Access And Time Zone Handling
To access databases restricted by network or security constraints, use the ServerIP column to redirect commands through a machine with permissions, running the TWebServivces. For time zone handling, the platform uses UTC for date and time tags, to manage conversions between UTC and local time use the DateTimeMode column .
→ Read more about at Datasets Advanced Topics.
Backup Of Solutions SQLite Data Bases
To back up SQLite databases, use the sqlite3
command to create a copy with .backup
, or use the Online Backup API for incremental and active-use backups. Ensure secure storage and regular testing of backup files for reliability.
→ Read more about at Datasets Advanced Topics.
Anchor | ||||
---|---|---|---|---|
|
Common Issues and Solutions
Troubleshooting and Best Practices
Table of Contents | ||||||
---|---|---|---|---|---|---|
|
Common #Issues and Solutions
#Issue:Connection loss between project and database
Database Timeout Configuration: The database may have a timeout setting that automatically disconnects idle connections after a certain period of time. It's recommended to check the database's timeout setting and adjust it, if necessary, to ensure that the connection remains active overnight.
Power Settings: It's also suggested to check the computer's power settings to ensure that it doesn's not entering t enter sleep or hibernation mode during a certain idle momentmoments, which could cause a loss of connection to the database. Adjusting these settings to keep the computer active during these idle moments may resolve the issue.
#Issue:Database Connection Problem
In the DB configuration, there is always a "Test" button to ensure that the connection is happening correctly. When there is a problem, the return of this button is an error message, usually returned by the database provider itself. The most common errors are: invalid user, invalid password, computer without access to the database, incorrect form of authentication.
#IssueIssue: Error accessing the Database Table
Once the connection is established, the Table configuration is specific to a table. In the "Table" combobox, the list of available tables automatically appears. It is possible, via script, to change which table will be accessed. However, care must be taken that the table exists and that the configuration is done using the correct name. The same care must be taken when Queries are used, as it is the user's responsibility to type the correct table name, as well as the syntax of the separators.
#ErrorError in the
syntaxSyntax of the Query
It is the user's responsibility to type the correct SQLStatement of a query using the QueryBuilder. Table name, column, values, all can generate an error if used incorrectly. For example: comparing different types may not return the expected result, strings in general should be in single quotes. The separators and clauses available can vary between databases, for . For example:
SQLServer
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT TOP 10 * FROM table WHERE column = value |
SQLite
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT * FROM table WHERE column = value LIMIT LIMIT 10; |
Oracle
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT * FROM table WHERE column = value AND ROWNUM <= 10; |
new Oracle version
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT * FROM table WHERE column = value FETCH ANDFIRST ROWNUM10 <=ROWS 10ONLY; |
or new Oracle versionIBM DB2
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT * FROM table WHERE column = value FETCH FIRST 10 ROWS ONLY; |
IBM DB2
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT * FROM table WHERE column = value FETCH FIRST 10 ROWS ONLY; |
ROWS ONLY; |
Oracle DB size limitation for nchar
The Oracle database has a size limitation of 2000 bytes for columns of the nchar
type. Some columns we were creating exceeded this limit, which caused the error. Specifically, the affected columns are:
TagsDictionary:
TagName
columnRuntimeUsers:
Profile
andPasswordHistory
columns
To address this, when the Dataset module detects an Oracle DB connection, it automatically adjusts the length of these columns from 2048 to 1999. For all other database providers, the column lengths remain unchanged.
ServerIP without TWebServer Running on the Remote Machine
In some cases, the computer may not have access to the database. In this case, it is possible to create a gateway, routing the commands to be executed on the computer that has access to the database. The ServerIP field should be configured with the IP and port (<IP>:<port>), pointing to this computer that has access permission. This computer must have the software with the TWebServer running installed. It will automatically perform this gateway service and send the commands to the database.
#DataTable returnedDataTable Returned NULL
When the return of a select or query is returned null, some error has occurred. Some common errors include: connection failure with the database, table not found, Dataset module is not running, incorrect query syntax. Check the return of the method using WithStatus when using a synchronous method or use the LastStatus and LastStatusMessage property when using asynchronous mode.
#DataTable returnedDataTable Returned with 0
rowsRows
When this happens, in general, there is a connection with the database and the table name is correct. In this case, the search condition is usually wrong, or the table is really empty. Check if the column names are correct and if the separators and clauses are valid.
#Dataset moduleDataset Module is
downDown
Although the TServer is responsible for forwarding requests to the database, the management and communication with the TServer is done by the Dataset module, as well as the treatment of responses. Therefore, if you are having basic problems with access and execution of database access, the first thing to check is whether the module is set up to run and is actually running.
#Very high response timeVery High Response Time
Sometimes, it may seem that access to the database is not being made, but what might actually be happening is that some accesses can return a very large amount of data, or the database may be overloaded, or with a bad configuration, causing it to have a low performance. Or even, the network itself can be overloaded and slow, and all these factors can impact the response time. In these cases, it is important to execute the Query directly in the database environment to be sure that the problem is not on the side of the database. Do this and check how long the database itself takes to execute the query. It is also worth checking the volume of data exchanged to have an idea of ?? the related side effects.
#UpdateUpdate of a table with the wrong schema (select before update)
The Dataset module uses ADO technology, and many things are resolved at the level of this API. When we are going to perform an Update on a table, the schema of the table and controls in the .Net NET DataTable type are used. Therefore, if you are going to perform an update passing a Tag or .net NET DataTable object as a parameter, it is important that this object respects the schema of the destination Table in the database. Normally, a Select command must have been given at some point to obtain the correct schema used by the bank. After this, it is easy to add, remove, and modify values in this DataTable and update it back to the physical table in the database.
#WhereWhere condition CaseSensitive
Case sensitivity in a WHERE
clause depends on the database and the configuration of the database you are using. For example, in MySQL, queries are case-insensitive by default, which means 'abc' and 'ABC' would be considered equal. However, this can be changed with specific database settings. In SQL Server, case sensitivity is also determined by the database configuration. In PostgreSQL, queries are case-sensitive by default, so 'abc' and 'ABC' would be considered different. Therefore, it really depends on the specific database and the settings of that database. If you need to ensure case-insensitivity in a query, you can use functions like UPPER()
or LOWER()
to convert all values to upper or lower case before comparison. For example:
Code Block | ||||
---|---|---|---|---|
| ||||
SELECT * FROM table WHERE LOWER(column) = LOWER(value); |
This query will return records where the column matches the value, regardless of capitalization.
Best Practices and #Recommendations
#recommendation: Error accessing the Database Table
Dataset Runtime Attributes
The Dataset namespace exposes properties and methods of the .NET objects used by the Dataset module execution.For more information on namespaces and objects, go to Objects and Attributes.
Dataset module Properties examples
Property
Type
Description
Example
CursorIndex
Integer
Represents the current position of a cursor within the result set of a query. It is an integer value that indicates the row number in the result set that the cursor points to, with the first row having an index of 0. The cursor can be used to navigate through the result set, allowing you to read, update, or delete rows of data.
Dataset.Query.QueryName.CursorIndex + 1
OpenStatusMessage
String
Provides a human-readable message describing the current state of the database connection. This can be useful for monitoring the connection status, diagnosing issues, or displaying the connection status to users in a user-friendly format.
Dataset.DB.DatabaseName.OpenStatusMessage
ConnectionString
String
Used to store the necessary information for establishing a connection to a database. It is a string value containing details such as server name, database name, authentication credentials, and other relevant parameters.
Dataset.DB.ProviderName.ConnectionString
Performance
The Dataset module's performance depends on many factors, including database performance, network latency, and the complexity of executing SQL queries. The platform will minimize overhead and execute queries as efficiently as possible. However, ultimately, the performance of the Dataset module is tied to these external factors. It's essential to design your database schema and queries with performance in mind and consider investing in high-quality hardware and network infrastructure to ensure optimal performance.
Best Practices and Recommendations
Error Handling
Error handling in the Dataset module is straightforward. If an error occurs during the execution of a command, the error message will update the module's Error property (Last Status). You can monitor this property to handle errors in your application. Furthermore, if an error occurs during the execution of a synchronous method, the process will return an empty DataTable and update the Error property. Alternatively, you can call methods like SelectCommandWithStatus
, where the status will be an output parameter in the method
.
In this section:
Page Tree | ||||
---|---|---|---|---|
|
...