DataDude 0.7.2

.NET Standard 2.0
Install-Package DataDude -Version 0.7.2
dotnet add package DataDude --version 0.7.2
<PackageReference Include="DataDude" Version="0.7.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DataDude --version 0.7.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: DataDude, 0.7.2"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. 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.7.2

// Install DataDude as a Cake Tool
#tool nuget:?package=DataDude&version=0.7.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

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 Versions
.NET net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows
.NET Core netcoreapp2.0 netcoreapp2.1 netcoreapp2.2 netcoreapp3.0 netcoreapp3.1
.NET Standard netstandard2.0 netstandard2.1
.NET Framework net461 net462 net463 net47 net471 net472 net48
MonoAndroid monoandroid
MonoMac monomac
MonoTouch monotouch
Tizen tizen40 tizen60
Xamarin.iOS xamarinios
Xamarin.Mac xamarinmac
Xamarin.TVOS xamarintvos
Xamarin.WatchOS xamarinwatchos
Compatible target framework(s)
Additional computed target framework(s)
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.7.2 1,227 8/4/2021
0.7.1 198 7/7/2021
0.7.0 195 3/10/2021
0.6.0 534 2/3/2021
0.5.1 176 2/3/2021
0.5.0 244 1/24/2021
0.4.0 264 12/27/2020
0.4.0-beta.8 199 12/21/2020
0.4.0-beta.7 199 12/21/2020
0.4.0-beta.6 138 12/14/2020
0.4.0-beta.5 147 12/14/2020
0.4.0-beta.4 150 12/14/2020
0.4.0-beta.3 158 12/14/2020
0.4.0-beta.2 135 12/8/2020
0.4.0-beta.1 184 12/5/2020
0.3.0-beta.2 153 12/1/2020
0.3.0-beta.1 179 11/27/2020
0.2.0-beta.1 202 11/27/2020
0.1.0-alpha.1 155 11/12/2020