The founding decision is specific: inside this operating environment, the relational row is already the most accurate representation of the business record. Replacing it with a DTO and mapping it back adds a second contract without removing the first.
DataRow is the runtime entity.
A DataRow arrives with more than values. It knows its table, schema, constraints, relations, original values, proposed values, and change state. Those capabilities are exactly what an editable enterprise application needs to bind, validate, compare, persist, reject, or merge a record.
The framework therefore does not copy a row into a separate entity class merely to regain those capabilities through another abstraction. Instead, ExtDataRow supplies typed, null-safe reads; flags; applicability and read-only evaluation; metadata access; and row-level operations. The result remains an ADO.NET row, but its ergonomics become appropriate for application code.
This is not a universal claim that every application should expose DataRow. It fits a governed Windows runtime operating near SQL Server, where the database contract is authoritative, the UI is trusted, and the same platform owns loading, editing, validation, and persistence. Public APIs, offline applications, and independently versioned clients require a different boundary.
There is no second property set that can drift from the result schema or omit a database capability.
DataRowState and DataRowVersion already distinguish unchanged, added, modified, deleted, original, and current values.
Windows Forms binds directly to DataTable and DataView, preserving sorting, filtering, currency, and edit state.
Columns remain available to editors, rules, formatting, validation variables, and persistence preparation.
A DataSet is a runtime package, not just a query result.
A named operation may return the primary entity table, lookup tables, command definitions, validation rules, aggregate data, and related records together. The DataSet keeps those tables and their relations in one transportable package. Controls can receive the complete context instead of making a chain of small, screen-specific requests.
ExtDataSet provides deterministic table lookup, relation setup, merging, and result reconciliation. ExtDataTable shapes tables, ensures calculated columns, selects rows, and prepares save payloads. ExtDataView creates the live filtered and sorted projection used by grids and cross-reference controls.
Master/detail is a configuration problem.
Master/detail does not require a typed DataSet or a predefined DataRelation. A named request can return an ordinary, untyped DataSet containing the complete working set. Configuration tells the framework which views depend on a master and which values connect them.
CtrlV owns and coordinates its child views. When its current row changes, it supplies the new parent context and each child updates its live view over the data already in memory. One CtrlV can manage several children, and because a child is itself a complete view, it can manage children of its own. The same behavior therefore builds two-level or multi-level screens without form-specific selection handlers.
The shared DataSet makes it possible to load all levels in one request, but it is the view hierarchy that manages the visual cascade. When no valid master is selected, its children remain empty rather than temporarily exposing unrelated rows.
The same untyped DataSet can also receive configured parent/child relations and constraints when the application needs relational navigation, integrity, or calculated expressions. Those relations enrich the data package; they are not required for CtrlV to manage its children. The visual hierarchy belongs to the controls, while the relational graph belongs to the data.
The extension layer becomes the model language.
Raw ADO.NET exposes object this[string] and uses DBNull. If every consumer performed its own casts, defaults, flag decoding, lookup, and metadata parsing, direct use of DataRow would become noisy and unsafe. The extensions are not cosmetic convenience methods; they are the missing language of the model.
| Component | Why it exists | Contribution |
|---|---|---|
ExtDataRow | Removes repeated casts, DBNull checks, flags, and row-state conditionals. | Typed reads, defaults, applicability, read-only evaluation, metadata, and row operations. |
ExtDataTable | Tables must be shaped and prepared consistently for UI and save operations. | Schema helpers, selection, cloning, calculated columns, and changeset preparation. |
ExtDataSet | Related tables arrive and return as one named runtime package. | Table discovery, relation wiring, merge, and reconciliation. |
ExtDataColumn | Columns carry expressions and descriptors used by rules and presentation. | Expression, metadata, default, and type-aware column behavior. |
TPars | Optional settings must evolve without adding one schema column per feature. | A compact key-value metadata language with typed interpretation. |
ExtFilter | Dynamic filters cannot safely be assembled through scattered string concatenation. | Composable expressions shared by views, grids, and cross-reference controls. |
The same philosophy extends to primitives, collections, concurrency, files, images, and reflection. Each family removes repeated boundary code so higher layers can work in framework concepts rather than defensive plumbing.
A framework grid remains a DataGridView and a framework entity remains a DataRow. Existing designer support, binding behavior, ADO.NET semantics, and the .NET type system remain available. The framework adds the missing operations without hiding the platform underneath.
A named request becomes a resolved runtime contract.
The DAL is not a thin SQL helper and not a repository facade over an ORM. A caller requests a dataset by stable name. The runtime determines which parameters are required, asks participating context providers to contribute them, applies security context first, prevents recursive re-entry, evaluates cache policy, executes the contract, and prepares the returned package.
A control does not need to know where a parameter came from. A user identifier may come from SC; an entity identifier from the current row; a filter value from a toolbar field; a relation identifier from CtrlXBase; and a date from a form. Each contributor marks the parameters it supplied. Unresolved requirements remain visible rather than silently becoming null.
This allows the same named operation to work from different screens. The command expresses the data it requires; the active runtime context assembles those requirements without the caller owning every participant.
The save path preserves the complete changeset.
Edits mutate the bound DataRows directly. A row retains original and current values while its state records whether it was added, modified, or deleted. Validation can therefore reason about both data and pending work before any persistence call occurs.
At save time, table and dataset helpers select the relevant changes, shape them into structured parameters, and send the set to a stored procedure in one contract. The database receives enough information to apply set-based logic, enforce its rules, and return authoritative results. Returned values are merged into the live dataset so generated identifiers, normalized values, and statuses become visible without rebuilding the screen.
The architecture is deliberate about its boundary.
Direct database contracts are an advantage when the application server and SQL Server operate inside a governed environment, network latency is controlled, users receive pixels through managed Windows sessions, and one platform owns both client and data behavior. Under those constraints, inserting HTTP, JSON, DTO, and mapping layers between WinForms and SQL Server would add operational surfaces without creating an independent public contract.
The same choice would be inappropriate for an untrusted public browser, an offline client, an independently versioned external API, or a system whose domain contract must remain independent of the database. The framework's maturity is visible not in claiming universality, but in matching the architecture to the environment it was designed to serve.
Next: see how metadata becomes a working interface.
The data runtime supplies the contract; the dynamic UI turns that contract into controls, relationships, commands, and validation.