Fake Data Generation & Database Seeding for Tuxedo ORM
Cufflink is a fake data generation library and CLI tool that uses Bogus to generate realistic test data based on your Tuxedo entity models. It automatically detects foreign key relationships, performs topological sorting for correct insert order, and uses bulk operations for high-performance data loading across SQL Server, PostgreSQL, MySQL, and SQLite.
dotnet add package Noundry.Tuxedo.Cufflink
dotnet tool install --global Noundry.Tuxedo.Cufflink.CLI
Uses Bogus to generate realistic data based on property names: Email, FirstName, Phone, Address, Price, and more.
Automatically detects foreign keys by naming convention (CategoryId -> Category) for int, long, and Guid types.
Determines correct insert order based on FK dependencies. Parent tables are populated before child tables.
Generate fake JSON data via auto-detection, JSON schemas, or custom generators.
Interactive wizard CLI, command-line mode for automation, and programmatic library usage.
Uses Tuxedo's high-performance bulk operations with configurable batch sizes.
# Install the CLI tool
dotnet tool install --global Noundry.Tuxedo.Cufflink.CLI
# Launch interactive wizard (recommended for beginners)
cufflink wizard
# Generate 1000 fake records per table
cufflink generate --records 1000
# Specify database provider and connection string
cufflink generate --records 500 \
--provider SqlServer \
--connection-string "Server=.;Database=TestDb;Integrated Security=true"
# Generate with JSON schema support
cufflink generate --records 1000 --json-schema-dir ./schemas
# Show information about discovered models
cufflink info
using Noundry.Tuxedo.Cufflink;
using Noundry.Tuxedo.Cufflink.Core;
var engine = new CufflinkEngine();
// Generate from assembly (scans for [Table] decorated classes)
await engine.GenerateFakeAsync(
assembly: typeof(Program).Assembly,
recordCount: 1000,
connectionString: "Data Source=app.db",
provider: DatabaseProvider.SQLite);
// Generate for specific model types
var types = new[] { typeof(Category), typeof(Product) };
await engine.GenerateFakeAsync(
modelTypes: types,
recordCount: 500,
connectionString: "Data Source=app.db",
provider: DatabaseProvider.SQLite);
var seedData = new Dictionary<Type, List<object>>
{
{
typeof(Category),
new List<object>
{
new Category { Id = 1, Name = "Electronics" },
new Category { Id = 2, Name = "Books" }
}
},
{
typeof(Product),
new List<object>
{
new Product { Id = 1, Name = "Laptop", Price = 999.99m, CategoryId = 1 },
new Product { Id = 2, Name = "Novel", Price = 14.99m, CategoryId = 2 }
}
}
};
await engine.SeedAsync(
seedData: seedData,
connectionString: "Data Source=app.db",
provider: DatabaseProvider.SQLite);
var builder = WebApplication.CreateBuilder(args);
// ... configure services ...
var app = builder.Build();
// Generate test data in development
if (app.Environment.IsDevelopment())
{
var engine = new CufflinkEngine();
await engine.GenerateFakeAsync(
assembly: typeof(Program).Assembly,
recordCount: 100,
connectionString: builder.Configuration.GetConnectionString("DefaultConnection")!,
provider: DatabaseProvider.SQLite);
}
app.Run();
Cufflink scans assemblies for classes decorated with [Table] attributes from Tuxedo. Use ModelScanner.ScanType() for single types or ModelScanner.ScanCurrentDirectory() for all DLLs.
Foreign keys are detected automatically by naming convention -- properties ending in "Id" (e.g., CategoryId references Category). Supports int, long, and Guid FK types. Nullable FKs require the [ForeignKey] attribute from Bowtie.
Tables are sorted by dependency order. Parent tables (no FKs) are inserted first, then child tables that reference them.
Categories (no dependencies)
|
Products (depends on Categories)
|
Orders (depends on Products)
Bogus generates realistic data based on property names and types:
public class User
{
public string Email { get; set; } // -> "john.doe@example.com"
public string FirstName { get; set; } // -> "John"
public string LastName { get; set; } // -> "Doe"
public string Phone { get; set; } // -> "(555) 123-4567"
public string Address { get; set; } // -> "123 Main Street, City, ST 12345"
public decimal Price { get; set; } // -> Random decimal
public DateTime CreatedAt { get; set; }// -> Recent past date
}
Uses Tuxedo's high-performance bulk operations to insert data efficiently in configurable batch sizes.
using Noundry.Tuxedo.Contrib;
[Table("Categories")]
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
[Table("Products")]
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
// Automatically detected as FK to Categories.Id (by naming convention)
public int CategoryId { get; set; }
// Guid FK also detected automatically
public Guid CreatedById { get; set; }
// Nullable FK: NOT detected -- use [ForeignKey] attribute
public int? OptionalCategoryId { get; set; }
}
Cufflink generates fake JSON data for columns detected as JSON types. Three approaches:
Automatically detects JSON columns by naming convention (Metadata, Settings, Config, Data, etc.).
Provide JSON schema files in a directory for structured fake JSON generation.
Use the [Column(TypeName = "jsonb")] attribute to explicitly mark JSON columns.
[Table("Products")]
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
// Auto-detected as JSON by name
public string Metadata { get; set; } = "{}";
// Explicitly marked as JSONB
[Column(TypeName = "jsonb")]
public string Settings { get; set; } = "{}";
}
// Quick way to generate data from ServiceProvider
await services.BuildServiceProvider()
.GenerateFakeDataAsync(
recordCount: 1000,
provider: DatabaseProvider.SQLite);
Core ORM that Cufflink generates data for. Define models with [Table], [Key], and other attributes.
Create the database schema before seeding with Cufflink. Provides [ForeignKey] for explicit FK declaration.
Import real CSV data instead of generating fake data.
HTTP API client library for fetching data from external APIs.