¿Cuál es la mejor manera de serializar rápidamente un DataReader sin usar DataTable (o usando una DataTable que podría tener nombres de columna duplicados)?

dapper datareader datatable

Pregunta

Almacenamos nuestras consultas de manera exhaustiva utilizando un decorador que envuelve IDbConnection / IDbCommand. Cuando algo llama 'ExecuteReader ()' usa el comando.text como clave de caché (por ejemplo, SELECT * FROM Foo ) y también podemos aplicar etiquetas a nuestros decoradores (por ejemplo, new FooDbCommand("UserCacheTag") ) para gestionar esto . El Reader se convierte a DataTable para ser claramente serializable y se puede volver a convertir utilizando la API DataTables (CreateDataReader).

Todo esto funciona brillantemente, pero hay un defecto.

Si el conjunto de registros entrante tiene nombres de columnas duplicados, cuando el IDataReader se traduce a una DataTable, los nombres de las columnas duplicadas se incrementan con un número (por ejemplo, 'PersonID1').

¿Cómo podemos crear nuestro IDataReader, que permite nombres de columnas duplicados, almacenables en caché (preferentemente serializables) y luego convertirlo a un IDataReader con los nombres de las columnas originales sin preocuparse de que los nombres de las columnas se alteren entre estados?

Información Adicional:

Usamos Dapper principalmente con el tipo de devolución dinámica para evitar estos problemas. Nos gustaría comenzar a utilizar el multimapping más. Pero si un tipo, digamos 'Persona', se devuelve varias veces en una consulta, aparecen nombres de columna duplicados.

Por ejemplo:

SELECT pEmployee.*, pManager.* 
FROM Persons pEmployee 
LEFT OUTER JOIN Persons pManager ON pManager.PersonID = pEmployee.ManagerPersonID

Respuesta popular

Lo logré creando mi propia clase DataTable que almacena el nombre de columna original en la propiedad 'Caption' y mi propio IDataReader que sobrescribe el método GetName () para buscar en la tabla de esquema. Es bastante directo, pero estoy seguro de que desearía que una DataTable simplemente tuviera una propiedad 'AllowDuplicateColumnNames'.

MyDataTable

Al cargar el DataReader, esto establecerá la propiedad 'Caption' en el nombre de la columna original. Al crear el DataReader, cambiará el nombre de la propiedad 'ColumnName' del esquema de nuevo al nombre original (actualmente almacenado en la columna Caption).

internal class MyDataTable : DataTable
    {
        public MyDataTable()
        {

        }

        /// <summary>
        /// This is a helper method which accounts for duplicate column names.
        /// In the loading process, it will rewrite the caption to be the original column name
        /// which can be a duplicate.
        /// </summary>
        /// <param name="dataReader"></param>
        public void LoadIDataReader(IDataReader dataReader)
        {
            var schemaTable = dataReader.GetSchemaTable();

            base.Load(dataReader);

            for (var i = 0; i < schemaTable.Rows.Count; i++)
            {
                var originalColumnName = schemaTable.Rows[i]["ColumnName"] as string;
                var currentColumnName = this.Columns[i].ColumnName;

                if(originalColumnName != currentColumnName)
                {
                    this.Columns[i].Caption = originalColumnName;
                }
            }
        }

        public IDataReader CreateIDataReader()
        {
            var dataReader = base.CreateDataReader();

            var schemaTable = dataReader.GetSchemaTable();

            for(var i = 0; i < schemaTable.Rows.Count; i++)
            {
                //this is reverse from above
                var originalColumnName = this.Columns[i].Caption;
                var currentColumnName = schemaTable.Rows[i]["ColumnName"] as string;

                if (originalColumnName != currentColumnName)
                {
                    schemaTable.Rows[i]["ColumnName"] = originalColumnName;
                }
            }

            return new MyDataReader(dataReader);
        }
    }

MyDataReader: IDataReader

Esto acepta un lector de datos y simplemente actúa como un decorador para el método GetName ().

internal class MyDataReader : IDataReader
    {
        private IDataReader _dataReader;

        public MyDataReader(IDataReader dataReader)
        {
            _dataReader = dataReader;
        }

        //other IDataReader methods not included for clarity

        public string GetName(int i)
        {
            return this.GetSchemaTable().Rows[i]["ColumnName"] as string;
        }
    }


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é