QueryMultiple conjunto de resultados orden modificada

c# dapper

Pregunta

Estoy ejecutando un procedimiento almacenado usando QueryMultiple para devolver múltiples conjuntos de datos.

var gridReader = db.QueryMultiple("sp", 
                                  parameters, 
                                  commandType: CommandType.StoredProcedure);

Puedo obtener fácilmente cada conjunto dado que sé el orden en que volverán.

SELECT * FROM dbo.Set1;
SELECT * FROM dbo.Set2;
SELECT * FROM dbo.Set3;
var set1 = gridReader.Read<Set1>();
var set2 = gridReader.Read<Set2>();
var set3 = gridReader.Read<Set3>();

Sin embargo, estoy en una situación en la que el orden en el que volverán puede cambiar. Otro desarrollador podría decidir cambiar el orden por cualquier razón. El procedimiento almacenado ahora se convierte en esto:

SELECT * FROM dbo.Set1;
SELECT * FROM dbo.Set3;
SELECT * FROM dbo.Set2;

¿Cómo puedo manejar esto?

Mi primer intento fue iterar cada cuadrícula, verificando los nombres de las columnas. Esto pareció funcionar bien al principio, pero no fui capaz de descubrir cómo proyectar la grilla en una clase, además de configurar manualmente cada campo. La razón principal por la que uso Dapper es para que pueda hacer esto por mí.

while (true)
{
    var grid = gridReader.Read();
    IDictionary<string, object> row = grid.FirstOrDefault();

    if (row == null)
        break;

    if (row.Keys.Contains("Set1_UniqueColumnName"))
    {
        // Need something like grid.Read<Set1>();
    }
    else if (row.Keys.Contains("Set2_UniqueColumnName")) { }
    else if (row.Keys.Contains("Set3_UniqueColumnName")) { }
}

Mi segunda idea fue leer cada cuadrícula en una clase, verificar los campos únicos de la clase para valores nulos / predeterminados y probar la siguiente clase si la prueba falló. Obviamente, esto no funcionará. .Read() devolverá la siguiente grilla de resultados. Esta solución me requeriría poder leer la misma grilla una y otra vez.

Respuesta aceptada

La respuesta de Davmos me indicó la dirección correcta. Necesario para usar una combinación de ADO.NET y Dapper. Básicamente, use ADO.NET para recuperar e iterar a través de los datos, pero use Dapper para analizar las filas en mis objetos. Tenga en cuenta el uso de FieldCount en el ciclo while en caso de que un conjunto de resultados realmente devuelva 0 filas. Queremos que avance al siguiente conjunto de resultados, no salga del ciclo.

Set1 set1 = null;
var set2 = new List<Set2>();
Set3 set3 = null;

using (var command = new SqlCommand("sp", conn))
{
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.AddRange(parameters);
    command.Connection.Open();

    using (var reader = command.ExecuteReader())
    {
        while (reader.FieldCount > 0)
        {
            var set1Parser = reader.GetRowParser<Set1>();
            var set2Parser = reader.GetRowParser<Set2>();
            var set3Parser = reader.GetRowParser<Set3>();

            var isSet1 = HasColumn(reader, "Set1_UniqueColumnName");
            var isSet2 = HasColumn(reader, "Set2_UniqueColumnName");
            var isSet3 = HasColumn(reader, "Set3_UniqueColumnName");

            while (reader.Read())
            {
                if (isSet1)
                {
                    set1 = set1Parser(reader);
                }
                else if (isSet2)
                {
                    set2.Add(set2Parser(reader));
                }
                else if (isSet3)
                {
                    set3 = set3Parser(reader);
                }
            }

            reader.NextResult();
        }
    }
}
public static bool HasColumn(IDataReader reader, string columnName)
{
    for (var i = 0; i < reader.FieldCount; i++)
    {
        if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
        {
            return true;
        }
    }

    return false;
}

Respuesta popular

Dapper proporciona un método de extensión IDataReader.GetRowParser que permite el cambio de tipo por fila. De los documentos Dapper aquí ...

Por lo general, querrá tratar todas las filas de una tabla dada como el mismo tipo de datos. Sin embargo, hay algunas circunstancias en las que es útil poder analizar diferentes filas como diferentes tipos de datos. Aquí es donde IDataReader.GetRowParser es útil.

Imagine que tiene una tabla de base de datos llamada "Formas" con las columnas: Id, Tipo y Datos, y desea analizar sus filas en los objetos Círculo, Cuadrado o Triángulo según el valor de la columna Tipo.

var shapes = new List<IShape>();
using (var reader = connection.ExecuteReader("select * from Shapes"))
{
    // Generate a row parser for each type you expect.
    // The generic type <IShape> is what the parser will return.
    // The argument (typeof(*)) is the concrete type to parse.
    var circleParser = reader.GetRowParser<IShape>(typeof(Circle));
    var squareParser = reader.GetRowParser<IShape>(typeof(Square));
    var triangleParser = reader.GetRowParser<IShape>(typeof(Triangle));

    var typeColumnIndex = reader.GetOrdinal("Type");

    while (reader.Read())
    {
        IShape shape;
        var type = (ShapeType)reader.GetInt32(typeColumnIndex);
        switch (type)
        {
            case ShapeType.Circle:
                shape = circleParser(reader);
                break;
            case ShapeType.Square:
                shape = squareParser(reader);
                break;
            case ShapeType.Triangle:
                shape = triangleParser(reader);
                break;
            default:
                throw new NotImplementedException();
        }

        shapes.Add(shape);
    }
}

Tendrá que obtener acceso al IDataReader que el GridReader envuelve o cambiar su código para usar los buenos objetos ADO.NET SqlConnection & SqlCommand antaño como este ...

using (command = new SqlCommand("sp", connection))
{
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.AddRange(parameters);

    using (var reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            // read row columns
        }
    }
}


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é