Quantcast
Channel: Brian Pedersen's Sitecore and .NET Blog
Viewing all articles
Browse latest Browse all 285

C# Connect to 2 or more databases using a Datacontext

$
0
0

This is more of a design pattern than it is a requirement. I use this technique when my application grows in size. When my application needs to connect to 2 or more databases, I use this encapsulation method to allow me to name my database connections before using them.

STEP 1: ADD 2 CONNECTION STRINGS TO THE appsettings.config

  "ConnectionStrings": {
    "Source": "************",
    "Destination": "************",
  },

STEP 2: MAKE 2 ALMOST IDENTICAL CLASSES, ONE FOR EACH CONNECTION STRING

The basic “DataContext” class looks like this:

using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;

namespace MyCode
{
    public class SourceDataContext
    {
        private readonly string _connectionString;

        public SourceDataContext(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("Source");
        }

        public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
    }
}

namespace MyCode
{
    public class DestinationDataContext
    {
        private readonly string _connectionString;

        public DestinationDataContext(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("Destination");
        }

        public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
    }
}

The only difference is the connection string name. These names are only as demonstration, although they could work in a production environment. Names like “ConsumerDatacontext” or “ProductsDatacontext” are probably more common.

STEP 3: ADD THE DataContext CLASSES IN THE Program.cs

Add both classes as singletons:

services.AddSingleton<SourceDataContext>();
services.AddSingleton<DestinationDataContext>();

Now I have some good names for my database connections. The connection string is hidden, and can now be changed without having to rename multiple code files. And I can add things like Azure Managed Identity to one or more connections without interfering with calling code.

STEP 4: USE THE CLASSES IN YOUR REPOSITORIES:

This piece of pseudocode is using Dapper to select from a table. What you should be focusing on is line 17, where I create the database connection.

using Dapper;
using Microsoft.Data.SqlClient;

namespace MyCode
{
    public class MyRepository
    {
        private readonly SourceDataContext _dataContext;

        public AdvertBrandRepository(SourceDataContext dataContext)
        {
            _destinationDataContext = destinationDataContext;
        }

        public async Task<IEnumerable<MyData>> GetAll()
        {
            using var connection = _sourceDataContext.CreateConnection();
            mydata = await connection.QueryAsync<MyData>($"SELECT * from MyTable");
            return mydata;
        }
    }
}

WHAT OTHER SHENANIGANS CAN YOÚ DO WHEN YOU HAVE A Datacontext class?

You can have the connection string og one database controlled by Azure Managed Identity, and another not.

See an example on how to use Azure Managed Identity here.

You can add all available table names to the Datacontext:

namespace MyCode
{
    public class SourceDataContext
    {
        private readonly string _connectionString;

        public SourceDataContext(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("Source");
        }

        public SqlConnection CreateConnection() => new SqlConnection(_connectionString);

        public string TableName1 = "TableName1";
        public string TableName2 = "TableName2";

    }
}

// Then use the table names in the code:

using Dapper;
using Microsoft.Data.SqlClient;

namespace MyCode
{
    public class MyRepository
    {
        ...
        ...

        public async Task<IEnumerable<MyData>> GetAll()
        {
            using var connection = _sourceDataContext.CreateConnection();
            mydata = await connection.QueryAsync<MyData>($"SELECT * from {_sourceDataContext.TableName1}");
            return mydata;
        }
    }
}

Or you can have an “IsEnabled” to allow yourself to do DryRuns:

namespace MyCode
{
    public class SourceDataContext
    {
        private readonly string _connectionString;

        public SourceDataContext(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("Source");
            // In this example, there is a setting called "SourceEnabled" in the config file
            Enabled = _configuration.Get<bool>("SourceEnabled");
        }

        public SqlConnection CreateConnection() => new SqlConnection(_connectionString);
        public bool Enabled { get; private set; };
    }
}

// Then use the enabled in your code:

using Dapper;
using Microsoft.Data.SqlClient;

namespace MyCode
{
    public class MyRepository
    {
        ...
        ...

        public async Task<IEnumerable<MyData>> GetAll()
        {
            if (!_sourceDataContext.Enabled)
                return Enumerable.Empty<MyData>();
            using var connection = _sourceDataContext.CreateConnection();
            mydata = await connection.QueryAsync<MyData>($"SELECT * from {_sourceDataContext.TableName1}");
            return mydata;
        }
    }
}

MORE TO READ:


Viewing all articles
Browse latest Browse all 285

Trending Articles