DEV Community

Cover image for Step-by-Step Guide: Querying From Databases Via a Single Database Helper Using the Strategy Design Pattern
David Au Yeung
David Au Yeung

Posted on • Edited on

Step-by-Step Guide: Querying From Databases Via a Single Database Helper Using the Strategy Design Pattern

This exercise allows you to get data from different databases (MySQL, PostgreSQL and SQL Server...) via a database helper.

Step 1: Define the Strategy Interface

First, create an interface ISQLStrategy that declares the method GetDataTable which will be implemented by different database strategies.

using System.Data;

namespace MyProject.Util
{
    public interface ISQLStrategy
    {
        DataTable GetDataTable(string sql);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement Concrete Strategies

Next, implement the ISQLStrategy interface for each database type (MySQL, PostgreSQL and SQL Server).

MySQL Strategy:

using MySql.Data.MySqlClient;
using System;
using System.Configuration;
using System.Data;

namespace MyProject.Util
{
    public class MySQLQuery : ISQLStrategy
    {
        public DataTable GetDataTable(string sql)
        {
            try
            {
                using (MySqlConnection conn = new MySqlConnection(ConfigurationManager.AppSettings["MySqlConnectionString"]))
                {
                    DataTable dt = new DataTable();
                    conn.Open();
                    MySqlCommand command = new MySqlCommand(sql, conn);
                    dt.Load(command.ExecuteReader());
                    conn.Close();
                    return dt;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

PostgreSQL Strategy:

using Npgsql;
using System;
using System.Configuration;
using System.Data;

namespace MyProject.Util
{
    public class NpgSqlQuery : ISQLStrategy
    {
        public DataTable GetDataTable(string sql)
        {
            try
            {
                using (NpgsqlConnection conn = new NpgsqlConnection(ConfigurationManager.AppSettings["NpgSqlConnectionString"]))
                {
                    DataTable dt = new DataTable();
                    conn.Open();
                    NpgsqlCommand command = new NpgsqlCommand(sql, conn);
                    NpgsqlDataAdapter _dap = new NpgsqlDataAdapter(command);
                    _dap.Fill(dt);
                    conn.Close();
                    return dt;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

SQL Server Strategy:

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

namespace MyProject.Util
{
    public class TSqlQuery : ISQLStrategy
    {
        public DataTable GetDataTable(string sql)
        {
            try
            {
                using (SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["TSqlConnectionString"]))
                {
                    DataTable dt = new DataTable();
                    conn.Open();
                    SqlCommand command = new SqlCommand(sql, conn);
                    SqlDataAdapter da = new SqlDataAdapter(command);
                    da.Fill(dt);
                    conn.Close();
                    return dt;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the Context Class

The SQLStrategy class will use an instance of ISQLStrategy to perform database operations.

using System.Data;

namespace MyProject.Util
{
    public class SQLStrategy
    {
        private readonly ISQLStrategy _sqlStrategy;

        public SQLStrategy(ISQLStrategy sqlStrategy)
        {
            _sqlStrategy = sqlStrategy;
        }

        public DataTable GetDataTable(string sql)
        {
            return _sqlStrategy.GetDataTable(sql);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Implement the Client Code

Finally, write the client code to test the strategy pattern implementation.

using System;
using System.Data;

namespace MyProject.Util
{
    public class Client
    {
        public static void Main()
        {
            SQLStrategy sqlHelper = new(new TSqlQuery());
            DataTable result = sqlHelper.GetDataTable("SELECT TOP (10) * FROM [Product]");

            foreach (DataRow row in result.Rows)
            {
                foreach (DataColumn column in result.Columns)
                {
                    Console.Write($"{column.ColumnName}: {row[column]} \t");
                }
                Console.WriteLine();
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Summary

  • Define the Strategy Interface: Create an interface ISQLStrategy with a method GetDataTable.
  • Implement Concrete Strategies: Implement the interface for MySQL, PostgreSQL, and SQL Server.
  • Create the Context Class: Use the SQLStrategy class to interact with the strategies.
  • Write Client Code: Test the implementation by querying a database.
  • This approach allows you to switch between different database implementations easily!

Full Coding

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using Npgsql;
using MySql.Data.MySqlClient;

namespace MyProject.Util
{
    //Strategy (Interface)
    public interface ISQLStrategy
    {
        DataTable GetDataTable(string sql);

        //You could add more methods for "Create", "Update" as well
    }

    //Concrete Strategies
    public class MySQLQuery : ISQLStrategy
    {
        public DataTable GetDataTable(string sql)
        {
            try
            {
                using (MySqlConnection conn = new MySqlConnection(ConfigurationManager.AppSettings["MySqlConnectionString"]))
                {
                    DataTable dt = new DataTable();

                    conn.Open();

                    MySqlCommand command = new MySqlCommand(sql, conn);

                    dt.Load(command.ExecuteReader());

                    conn.Close();

                    return dt;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());

                return null;
            }
        }
    }

    public class NpgSqlQuery : ISQLStrategy
    {
        public DataTable GetDataTable(string sql)
        {
            try
            {
                using (NpgsqlConnection conn = new NpgsqlConnection(ConfigurationManager.AppSettings["NpgSqlConnectionString"]))
                {
                    DataTable dt = new DataTable();

                    conn.Open();

                    NpgsqlCommand command = new NpgsqlCommand(sql, conn);

                    NpgsqlDataAdapter _dap = new NpgsqlDataAdapter(command);

                    _dap.Fill(dt);

                    conn.Close();

                    return dt;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());

                return null;
            }
        }
    }

    public class TSqlQuery : ISQLStrategy
    {
        public DataTable GetDataTable(string sql)
        {
            try
            {
                using (SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["TSqlConnectionString"]))
                {
                    DataTable dt = new DataTable();

                    conn.Open();

                    SqlCommand command = new SqlCommand(sql, conn);

                    SqlDataAdapter da = new SqlDataAdapter(command);

                    da.Fill(dt);

                    conn.Close();

                    return dt;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());

                return null;
            }
        }
    }

    //Context
    public class SQLStrategy
    {
        public ISQLStrategy _sqlStrategy;

        public SQLStrategy(ISQLStrategy sqlStrategy)
        {
            _sqlStrategy = sqlStrategy;
        }

        public DataTable GetDataTable(string sql)
        {
            return _sqlStrategy.GetDataTable(sql);
        }
    }

    // Testing the Strategy Design Pattern
    // Client Code
    public class Client
    {
        public static void Main()
        {
            SQLStrategy sqlHelper = new(new TSqlQuery());

            DataTable result = sqlHelper.GetDataTable("SELECT TOP (10) * FROM [Product]");

            foreach (DataRow row in result.Rows)
            {
                foreach (DataColumn column in result.Columns)
                {
                    Console.Write($"{column.ColumnName}: {row[column]} \t");
                }

                Console.WriteLine();
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Love C#!

Top comments (0)