Test Data Generator

Select tables, configure realistic fields and distributions, preview related rows, and append repeatable test data from Studio.

Direct connections. The first version supports one directly connected database, including Studio's hybrid incremental-durable mode. Existing rows are preserved. Remote, routed and sharded targets are not enabled.

Getting Started

  1. Open Tools → Test Data Generator, find it in the command palette, or choose a table's Generate Test Data... action.
  2. Select tables and enter the exact number of new rows for each. Zero rows is allowed.
  3. Review suggested generators in Fields. Use Options to configure ranges, weights, date windows, lengths and null rates.
  4. Open Relationships and choose whether each parent-key source is generated or existing. Select any missing generated parent explicitly.
  5. Set a repeatable seed and a UTC reference date. Choose Preview data to validate the full run and inspect a sample.
  6. Review the target, counts and generation order. Choose Generate data to append all selected tables in one transaction.
  7. Save a profile to reuse the settings and download a run summary to record the outcome.

For example, generate 100 customers and 500 orders together, with the orders using generated customer keys. To add orders for customers already in the database, select only Orders and choose Use existing parent rows.

Field Generators

Choices follow the column's declared SQL type. Generated values use the same assignment rules as the database, including integer ranges, decimal precision and scale, text/binary lengths and temporal facets.

Field familyAvailable behavior
Integer, real, decimalSequences and bounded numbers. Unique keys are checked against existing and generated values.
Person and contactFirst name, last name, full name, email and phone. Full name and email reuse FirstName/LastName in the same row when present.
Address and descriptive textStreet, city, region, postal code, country, company, product and prose, with configurable lengths.
Boolean, UUID, date/time, binaryTyped generation. Dates depend on the saved UTC reference date. Binary constants and list values use hexadecimal input.
JSON and XMLConstants or value lists validated through the database's assignment rules.
Constants, value lists, defaultsType-checked values. Supported deterministic defaults are evaluated during preview and written explicitly.
RowversionOmitted from inserts and labeled Engine generated in preview.

Generated emails use example.test and preserve the domain within the configured length. Independently generated city, region and postal-code values are plausible samples; they do not guarantee a matching geographic address.

Distributions

DistributionMeaning
UniformEqual probability across the configured choices or range.
Weighted categoriesOne nonnegative relative weight per value, with a finite positive total. Zero-weight categories are excluded.
Bounded normalNumeric samples stay within the range. The mean must be in range and deviation must be positive and no larger than the range.
Recent datesThe selected probability draws from the recent window; the remainder draws from the full window, which also includes recent dates.
Hot keysThe selected probability draws from the first 20% of a stable parent-key order; the remainder draws from the entire pool. This does not rank real usage.
Null rateA per-row probability, subject to column and relationship nullability.

Probabilities describe sampling behavior, not exact category quotas. A small preview will not necessarily match the configured percentages.

Relationships and Constraints

Declared foreign keys are included automatically. For a schema without a declared FK, add an explicit logical mapping and enter child and parent columns in matching order. Parent columns must identify an ordered primary or unique key.

  • Generated parents: selected parent tables run before their children.
  • Existing parents: keys come from actual rows, including sparse integers, text and composite keys.
  • Composite keys: the generator selects complete parent tuples and preserves column order.
  • One-to-one mappings: parent keys are selected without replacement; parent tuples already used by existing unique children are excluded.
  • Overlapping columns: shared columns such as tenant IDs are coordinated; incompatible mappings fail validation.
  • Nullable references: an explicit null policy is supported where the mapped columns allow it.

The planner checks primary and unique keys, collations, nullability, logical types, identity allocation and relationship membership. Supported CHECK/default expressions include literals, column references, arithmetic, comparisons, AND/OR/NOT, IN, BETWEEN, IS NULL and COLLATE. Unsupported expressions are reported, not skipped.

These checks validate the selected rules. They do not automatically solve arbitrary business constraints. Database constraints and indexes remain active during insertion.

Preview and Repeatability

Preview data validates every requested row, then displays up to 25 rows per page by default. Changing a setting invalidates the prepared preview. The parent-key disclosure shows the reference for the first displayed row, even if that parent lies outside its first preview page.

Preview reads schema and existing key projections in a consistent read transaction. It never inserts rows or fires INSERT triggers. Rowversion values are supplied by the engine during insertion and are labeled accordingly.

A resolved run depends on the seed, versioned profile, fixed UTC reference date, provider version and locale, schema identities, requested counts, relationship choices and existing keys. Paging, table display order and insert batch size do not consume or alter other rows' random streams.

The algorithm identifier is sha256-splitmix64-v1/bogus-35.6.5/net10, using the English provider catalog. Historical output from the old process-dependent seed algorithm is intentionally not preserved. Appending again changes existing key state and allocation, so it produces a new resolved run even with the same seed.

Profiles and Run Summaries

Save profile downloads the configuration as JSON. Load profile restores it and checks its schema identities against the connected database. Recreated tables with different identities need a new configuration. Profiles are limited to 1 MB and reject unknown properties or incompatible versions.

Profiles contain settings and schema identities, not existing database rows or connection credentials. A profile is reusable configuration; it does not freeze a populated database's key state.

Save run summary records the seed, algorithm, reference date, profile hash, schema/key snapshot fingerprints, target, requested and inserted row counts, duration and outcome.

Transactions and Cancellation

Generate pins the selected connection and opens one transaction for all selected tables. It rereads relevant schema, identity state, triggers, counts and keys before inserting. Changes since preview require a new preview.

Rows are streamed in bounded batches in dependency order. Progress is uncommitted until the final receipt says Committed. Persisted counts and key tuples are checked before commit, and a confirmed commit refreshes affected Studio views.

Cancellation, closing the tab and database switching stop pending work and await cleanup. A known failure before commit rolls back all inserted rows. Commit and rollback use an independent cleanup token; cancellation cannot undo a completed commit.

Unknown outcome. If a commit acknowledgement is lost or rollback cannot be confirmed, the receipt says Unknown, reports no confirmed inserted counts and blocks another run in that tab. Inspect the database before starting again. There is no automatic retry.

Host Limits

The optional top-level TestDataGeneration host configuration section overrides these defaults:

SettingDefault
MaxRows10,000 across the run
MaxGeneratedBytes33,554,432 (32 MiB estimated generated values)
MaxKeyBytes33,554,432 (32 MiB estimated keys and validation structures)
MaxExistingKeyRows100,000 per table whose keys are read
MaxStatementBytes262,144 (256 KiB UTF-8 SQL)
BatchSize100 rows
PreviewRows25
TimeoutSeconds120 before commit/cleanup

Rows and existing-key rows can be configured up to 1,000,000, batches up to 1,000, preview pages up to 100, statements from 1 KiB to 4 MiB, and the pre-commit timeout up to 600 seconds. Invalid limits are rejected when the generator initializes. Larger limits need workload-specific qualification.

Size accounting estimates values and key structures; it does not cap total process memory or database WAL size. Oversized plans do not fall back to partial commits.

Supported Scope

The first version appends to writable SQL tables through a direct connection, including direct hybrid incremental-durable mode. Self-references may use existing parent rows.

Generated relationship cycles and self-cycles, rowversion keys, INSERT-trigger tables, LIKE/CAST/function/subquery preflight expressions, interval and bit-string fields, internal/system tables, remote connections, routed/sharded targets, collections and replace/truncate operations are outside the enabled scope.

Shared Library: CSharpDB.DataGeneration

The .NET 10 library contains the shared generation engine and schema planner. Studio and the developer CLI reference it. It does not open database connections, manage transactions, render UI or write output files.

APIResponsibility
GenerationProfileVersioned table, field and relationship settings, JSON serialization and profile hash.
GenerationTableSnapshotCaller-supplied schema, indexes, counts, key projections, triggers and fingerprint.
GeneratorCatalogCompatible providers, suggestions, field options and generated values.
GenerationPlanFull-run validation, dependency order, key allocation, indexed rows and referenced parent keys.
GenerationValuesEngine-compatible assignment, collation-aware keys, supported expression evaluation and SQL formatting.
StableRandomVersioned seed derivation and independent random streams.
SpecDataGeneratorThe developer specification evaluator with lazy SQL and document row sources.

Given a complete snapshot supplied by an adapter, callers can suggest rules, validate the run and request a preview page:

using CSharpDB.DataGeneration;

static GenerationPlan PreparePreview(GenerationTableSnapshot snapshot)
{
    var table = GenerationPlan.Suggest(snapshot);
    table.Rows = 100;
    var profile = new GenerationProfile
    {
        Seed = 42,
        ReferenceUtc = new DateTime(2026, 9, 11, 0, 0, 0, DateTimeKind.Utc),
        Tables = [table],
    };

    // Supply additional parent snapshots when the table has relationships.
    return GenerationPlan.Build(profile, [snapshot]);
}

// The resulting plan exposes Rows(tableName, offset: 0, count: 25).

Database adapters must supply actual schema identities, type facets, checks, key/index metadata, identity state, trigger metadata, counts and required existing keys. Include snapshots for unselected parent tables too. An empty snapshot is only appropriate for a truly empty table.

Studio's TestDataGenerationAdminService handles transaction-consistent reads, client capture, append execution, cancellation and outcome reporting. The library depends on CSharpDB.Primitives, CSharpDB.Sql, CSharpDB.Execution and Bogus 35.6.5, reusing engine assignment and collation rules.

Package status: this project currently has IsPackable=false and is not included in the NuGet release list or the CSharpDB umbrella package. Consume it by project reference in the repository. Its project README provides the library overview; this page is the full feature documentation.

Developer CLI

tests/CSharpDB.DataGen remains the developer utility for specification-driven relational, document and time-series datasets, schema inference, file output and direct loading. Its evaluator and specification models now live in the shared library while retaining the CSharpDB.DataGen namespaces.

dotnet run --project tests/CSharpDB.DataGen/CSharpDB.DataGen.csproj -- relational --rows 1000 --seed 42 --reference-date 2026-09-11

Keep the specification, options, seed, reference date and provider/runtime version unchanged to reproduce data files across processes. The CLI reference date defaults to 2026-03-28 UTC. Run summaries also contain operational paths and timings.

Schema inference uses declared types before name heuristics and excludes internal tables. It does not reconstruct arbitrary constraints or general foreign-key relationships. Use Studio's planner for validated appends against actual connected keys.

Verification

The initial focused qualification passed 67 tests: 25 generator/CLI integration cases, 39 Studio lifecycle/navigation/client-holder cases and 3 transaction-snapshot cases. Coverage includes typed round trips, distribution samples, composite/overlapping/one-to-one keys, stale plans, limits, late SQL errors, cancellation, database switching, tab disposal and a lost commit acknowledgement.

Browser checks covered generated and existing parents, weighted-rule validation, profile save/load, paging, parent-key disclosure, commit/count refresh, summary downloads and dark/light layouts. The final checked browser session had no warnings or errors.

A local 10,000-row run on September 11, 2026 used Windows 11 build 26200, .NET 10.0.12, an Intel Core i9-11900K with 16 logical CPUs, and direct hybrid incremental-durable storage. The fixture contained 1,000 customers with names/emails and 9,000 orders with integer keys and decimal amounts, identity/primary keys, one FK, an FK lookup index and an amount CHECK.

MeasurementObserved result
Full validation and preview2.53 seconds
Insert, verify and commit2.71 seconds
Estimated generated valuesAbout 1.03 MB

These are local observations, not throughput guarantees or general qualification for larger limits. To run the focused generator checks from the repository root:

dotnet test tests/CSharpDB.DataGeneration.Tests/CSharpDB.DataGeneration.Tests.csproj

Related guides: Studio / Admin UI, SQL Data Types, Database Modes, and Database DevOps.