Envolviendo múltiples consultas con múltiples salidas

c# dapper generics refactoring sql

Pregunta

Tengo esta clase, en la que estoy envolviendo llamadas aptas para hacer algo como

var results = SqlWrapper.ExecuteQuery<Product,Customer>("SELECT id FROM Products; SELECT id FROM Customers;");

Dónde

results[0] = List<Product>
results[1] = List<Customer>

Admito 1,2,3 objetos de salida, pero me gustaría arbitraria. La clase también es fea y está llena de código de copia y pegado. Tengo en cuenta si deseo volver a utilizar una conexión al pasar una conexión de manera opcional, pero el código parece estar sucio. Lo que realmente me gustaría es una forma de definir params T[] pero como entiendo eso no funciona. ¿Es esta la forma en que este código puede ser limpiado / acortado?

using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Dapper;

namespace SqlWrapper
{
    public static class SqlWrapper
    {
        private const string SqlConnectionString = "Server=localhost;Database=TTDS;User Id=sa;Password=sa;";


        public static List<T> ExecuteQuery<T>(string sql, object param = null, SqlConnection sqlConnection = null)
        {
            if (sqlConnection != null)
            {
                return sqlConnection.Query<T>(sql, param).ToList();
            }

            using (var tempSqlConnection = new SqlConnection(SqlConnectionString))
            {
                tempSqlConnection.Open();
                return tempSqlConnection.Query<T>(sql, param).ToList();
            }
        }


        public static List<dynamic> ExecuteQuery<T1, T2>(string sql, object param = null, SqlConnection sqlConnection = null)
        {
            if (sqlConnection != null)
            {
                return MultiQuery<T1, T2>(sqlConnection, sql, param);
            }

            using (var tempSqlConnection = new SqlConnection(SqlConnectionString))
            {
                return MultiQuery<T1, T2>(tempSqlConnection, sql, param);
            }
        }

        public static List<dynamic> ExecuteQuery<T1, T2, T3>(string sql, object param = null,
            SqlConnection sqlConnection = null)
        {
            if (sqlConnection != null)
            {
                return MultiQuery<T1, T2, T3>(sqlConnection, sql, param);
            }

            using (var tempSqlConnection = new SqlConnection(SqlConnectionString))
            {
                return MultiQuery<T1, T2, T3>(tempSqlConnection, sql, param);
            }
        }

        private static List<dynamic> MultiQuery<T1, T2>(SqlConnection sqlConnection, string sql, object param = null)
        {
            var rv = new List<dynamic>();

            using (var grid = sqlConnection.QueryMultiple(sql, param))
            {
                rv.Add(grid.Read<T1>().ToList());
                rv.Add(grid.Read<T2>().ToList());
            }

            return rv;
        }

        private static List<dynamic> MultiQuery<T1, T2, T3>(SqlConnection sqlConnection, string sql, object param = null)
        {
            var rv = new List<dynamic>();

            using (var grid = sqlConnection.QueryMultiple(sql, param))
            {
                rv.Add(grid.Read<T1>().ToList());
                rv.Add(grid.Read<T2>().ToList());
                rv.Add(grid.Read<T3>().ToList());
            }

            return rv;
        }


        public static void ExecuteNonQuery(SqlConnection sqlConnection, string sql, object param, int? timeout = null)
        {
            if (sqlConnection != null)
            {
                sqlConnection.Execute(sql, param, commandTimeout: timeout);
            }
            else
            {
                using (var tempSqlConnection = new SqlConnection(SqlConnectionString))
                {
                    tempSqlConnection.Open();
                    tempSqlConnection.Execute(sql, param, commandTimeout: timeout);
                }
            }
        }
    }
}

Respuesta aceptada

Aquí hay un código no probado que demuestra un par de ideas que tenía.

  1. Si bien "usar" es bastante sorprendente, puede reducir el código en algunos casos si, opcionalmente, crea la conexión primero y luego, si es necesario, elimina el sqlConnection en un bloque finally.
  2. Si devuelve un Tuple<List<T>,List<U>,List<V>> puede tener valores de retorno fuertemente tipados que puede usar fácilmente
  3. Si llama a su función más compleja de las que son menos complejas, puede minimizar su código duplicado.

public static class SqlWrapper
{
    private const string SqlConnectionString = "Server=localhost;Database=TTDS;User Id=sa;Password=sa;";

    private class NoResult { }

    public static List<T1> ExecuteQuery<T1>(string sql, object param = null, SqlConnection sqlConnection = null)
    {
        return ExecuteQuery<T1, NoResult, NoResult>(sql, param, sqlConnection).Item1;
    }

    public static Tuple<List<T1>, List<T2>> ExecuteQuery<T1, T2>(string sql, object param = null, SqlConnection sqlConnection = null)
    {
        var result = ExecuteQuery<T1, T2, NoResult>(sql, param, sqlConnection);
        return Tuple.Create(result.Item1, result.Item2);
    }

    public static Tuple<List<T1>, List<T2>, List<T3>> ExecuteQuery<T1, T2, T3>(string sql, object param = null, SqlConnection sqlConnection = null)
    {
        List<T1> list1;
        List<T2> list2 = null;
        List<T3> list3 = null;
        bool needsDisposed = false;

        if (sqlConnection == null)
        {
            sqlConnection = new SqlConnection(SqlConnectionString);
            sqlConnection.Open();
            needsDisposed = true;
        }

        try
        {
            using (var grid = sqlConnection.QueryMultiple(sql, param))
            {
                list1 = grid.Read<T1>().ToList();
                if (typeof(T2) != typeof(NoResult))
                {
                    list2 = grid.Read<T2>().ToList();
                }
                if (typeof(T3) != typeof(NoResult))
                {
                    list3 = grid.Read<T3>().ToList();
                }

                return Tuple.Create(list1, list2, list3);
            }
        }
        finally { if (needsDisposed) sqlConnection.Dispose(); }
    }


    public static void ExecuteNonQuery(SqlConnection sqlConnection, string sql, object param, int? timeout = null)
    {
        bool needsDisposed = false;

        if (sqlConnection == null)
        {
            sqlConnection = new SqlConnection(SqlConnectionString);
            sqlConnection.Open();
            needsDisposed = true;
        }

        try { sqlConnection.Execute(sql, param, commandTimeout: timeout); }
        finally { if (needsDisposed) sqlConnection.Dispose(); }
    }
}


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué