Conditionally select between different DbContext.DbSet (as template-parameter)?

880 views Asked by At

Scenario: I have an existing database where I operate on. I transform data and map them into new tables. To easy validation of these transformations I need to put them into seperate tables (prefixed with Test_). But I still need the functionality of the production-layout. Therefore I somehow must give the target-table as a template parameter to the transform-task (Process()).

// existing Models
public virtual class DataRecord1
{
    public Int32 Id { get; set; }
    ...
}
public virtual class DataRecord2
{
    public Int32 Id { get; set; }
    ...
}

// new Tables
public virtual class Test_DataRecord1 : DataRecord1
{}
public virtual class Test_DataRecord2 : DataRecord2
{}

public partial class DatabaseContext : DbContext
{
    public virtual DbSet<DataRecord1> DataRecord1 { get; set; }
    public virtual DbSet<DataRecord2> DataRecord2 { get; set; }
    // Test
    public virtual DbSet<Test_DataRecord1> Test_DataRecord1 { get; set; }
    public virtual DbSet<Test_DataRecord2> Test_DataRecord2 { get; set; }
}

The transformation might use multiple context-instances across multiple functions, so passing the context is not an option.

public class ProcessTask
{
        // transform data
    public void Process()
    {
        using( var context = new DatabaseContext() )
        {
            context.Configuration.AutoDetectChangesEnabled = false;

            var data1 = context.DataRecord2
                .Where( ... )
                .ToList();
            var data2 = context.DataRecord1
                .Where( ... )
                .ToList();

            // operate and transform data 

            context.DataRecord1.AddRange( ... );

            context.ChangeTracker.DetectChanges();
            context.SaveChanges();
        }

        this.SubProcess();
    }

    private void SubProcess()
    {
        using( var context1 = new DatabaseContext() )
        using( var context2 = new DatabaseContext() )
        {
            // operate on the data
        }
    }
}

public static class Main()
{
    // current use:
    new ProcessTask().Process();
    // new functionality:
    new ProcessTask<Mode.Test>.Process(); // somehow change the task, so that Test_DataRecord is used
}

How do I modify Process() to conditionally select between DataRecords and Test_DataRecords?

1

There are 1 answers

5
Sefe On

You can parametrize your Process method with a selector method:

private void Process<T>(Func<DatabaseContext , DbSet<T>> selector)
    where T : DataRecord
{
    using( var context = new DatabaseContext() )
    {
        var dataRecords = selector(context);
        context.Configuration.AutoDetectChangesEnabled = false;

        var data = dataRecords
            .Where( ... )
            .ToList();

        // operate and transform data 

        dataRecords.AddRange( ... );

        context.ChangeTracker.DetectChanges();
        context.SaveChanges();
    }
}

You can call this method for your different sets:

public void ProcessDataRecord()
{
    Process(context => context.DataRecords);
}


public void ProcessTest_DataRecord()
{
    Process(context => context.Test_DataRecords);
}