DataDude 0.6.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package DataDude --version 0.6.0
NuGet\Install-Package DataDude -Version 0.6.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DataDude" Version="0.6.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DataDude --version 0.6.0
#r "nuget: DataDude, 0.6.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DataDude as a Cake Addin
#addin nuget:?package=DataDude&version=0.6.0

// Install DataDude as a Cake Tool
#tool nuget:?package=DataDude&version=0.6.0

Data dude

Data Dude is a library to help create test data based on the database schema. Data dude is inspired by CaptainData but its internals and strategy differs a bit which is supposed to make it more extendable and configurable.

Get started with Data dude:

await new DataDude()
    .Insert("Department")
    .Insert("Employee", new { Name = "John Doe" }, new { Name = "Jane Doe" })
    .Go(connection);

Concepts

Data dude is at its core an instruction handler, which means that it handles instructions. Built in are insertions and execution handling.

Inserts

Inserts are what Data dude does best. It can insert rows based on schema-knowledge and configurable handling. That way you should be able to just specify the data you acually care about. Other column values should be taken care of by the dude. With its default configuration it should be able to handle most cases, but when you encounter edge cases or want to re-configure the default behavior, there are some knobs to tweak:

Automatic Foreign Keys

This is a concept where Data dude can utilize the schema information and fill in foreign key column values based on previos inserts. This functionality can be enabled like so:

await new DataDude()
    .EnableAutomaticForeignKeys()
    .Insert("A")
    .Insert("B")
    .Go(connection);

In this example, if table B has a foreign key to table A, then Data dude will automatically set the corresponding foreign keys so a row can be inserted to table B without specifically specifying these keys manually.

This concept can be taken taken even a bit further by instructing Data dude to dynamically add missing foreign keys, like so:

await new DataDude()
    .EnableAutomaticForeignKeys(x => x.AddMissingForeignKeys = true)
    .Insert("B")
    .Go(connection);

In this example, if table B has a foreign key to table A, then Data dude will automatically generate an insert instruction for table A before the table B -instruction. Foreign keys will then be handled in the same way as in the example above.

To make matters a bit more complicated, you might not always want foreign keys to automatically be inserted. You might for instance not want nullable or recursive foreign keys inserted. The strategy can be configured by setting the DependencyTraversalStrategy configuration like so:

new Dude()
    .EnableAutomaticForeignKeys(x =>
    {
        x.AddMissingForeignKeys = true;
        x.DependencyTraversalStrategy = DependencyTraversalStrategy.SkipNullableForeignKeys
    })

Data dude comes preconfigured with 3 dependency traversal strategy options:

  • FollowAllForeignKeys: Default strategy will attempt to generate inserts for all foreign keys
  • SkipRecursiveForeignKeys: Will not attempt to generate inserts for foreign keys where the table has a reference to itself
  • SkipNullableForeignKeys: Will not attempt to generate inserts for nullable foreign keys If you want more control you can create your own class that implements IDependencyTraversalStrategy and plug it in like above.
InsertValueProviders

They provide default column values for the usual data types before an insert is made. If you want to add your own default values, you can configure them using shorthand like this:

await new DataDude()
    .ConfigureCustomColumnValue((column, value) => 
    {
        if (column.Name == "Active")
        {
            value.Set(new ColumnValue(true));
        }
    })
    .Insert("Employee")
    .Go(connection);

... or if you have more complex logic you can create your own value provider and add it like so:

public class ActiveUserValueProvider : IValueProvider
{
    public void Process(ColumnInformation column, ColumnValue previousValue)
    {
        if (previousValue.Type == ColumnValueType.NotSet &&
            column.DataType == "bit" &&
            column.Table.Name == "User" &&
            column.Name == "Active")
        {
            previousValue.Set(new ColumnValue(true));
        }
    }
}

dude.ConfigureInsert(x => x.InsertValueProviders.Add(new ActiveUserValueProvider()));
InsertInterceptors

These are executed before and after inserts (but after value providers have been executed). By default only one interceptor, IdentityInsertInterceptor is configured (which handles setting and resetting identity inserts when needed). Another one can be configured using .EnableAutomaticForeignKeys() which is an interceptor that attempts to set foreign keys for you based on previously inserted valued. You can also add your own interceptor like so:

public class AlwaysTrue : IInsertInterceptor
{
    public Task OnInsert(InsertStatement statement, InsertContext context, IDbConnection connection, IDbTransaction? transaction = null)
    {
        foreach (var (column, value) in statement.Data)
        {
            if (column.DataType == "bit")
            {
                value.Set(new ColumnValue(true));
            }
        }

        return Task.CompletedTask;
    }

    public Task OnInserted(InsertedRow insertedRow, InsertStatement statement, InsertContext context, IDbConnection connection, IDbTransaction? transaction = null)
        => Task.CompletedTask;
}

dude.ConfigureInsert(x => x.InsertInterceptors.Add(new AlwaysTrue()));
InsertRowHandlers

These are the handlers that do the actual insertion. Only the first insert handler that can handle the insert statement gets to execute the insert and return the inserted row. By default there are two insert handlers:

  • IdentityInsertRowHandler handles insertion when there is only one primary key with identity. The inserted row retrieved using SCOPE_IDENTITY()
  • GeneratingInsertRowHandler handes inserts by generating unspecified primary keys when possible*

*) Uses specified default column values if possible, if not available will generate keys if data type is one if uniqueidentifier, nvarchar, varchar, shortint, int, bigint.

There is one other insert handler available, OutputInsertRowHandler which uses OUTPUT identity.* to get ahold of the inserted row, not enabled by default since the default two should cover most bases and since it it also needs to disable any table triggers in order to perform the insert, which might not be what you want. If you do want to use it, it can be plugged in like this:

dude.ConfigureInsert(x => x.InsertRowHandlers.Add(new OutputInsertRowHandler()));

Dependencies

  • Dapper is used for internal data access
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.8.0-preview.5 608 3/11/2023
0.8.0-preview.4 4,276 2/21/2023
0.8.0-preview.3 86 2/21/2023
0.8.0-preview.2 85 2/20/2023
0.8.0-preview.1 88 2/20/2023
0.7.2 3,085 8/4/2021
0.7.1 356 7/7/2021
0.7.0 444 3/10/2021
0.6.0 706 2/3/2021
0.5.1 309 2/3/2021
0.5.0 383 1/24/2021
0.4.0 407 12/27/2020
0.4.0-beta.8 243 12/21/2020
0.4.0-beta.7 244 12/21/2020
0.4.0-beta.6 185 12/14/2020
0.4.0-beta.5 194 12/14/2020
0.4.0-beta.4 198 12/14/2020
0.4.0-beta.3 208 12/14/2020
0.4.0-beta.2 182 12/8/2020
0.4.0-beta.1 231 12/5/2020
0.3.0-beta.2 201 12/1/2020
0.3.0-beta.1 226 11/27/2020
0.2.0-beta.1 252 11/27/2020
0.1.0-alpha.1 205 11/12/2020