Files
Plataforma-de-desarrolladores/AGENTS_DATA_READER_MAPPING.md
Jorge Luis caudillo esparza 6685ef63fb Initial commit
2026-07-14 11:15:57 -07:00

4.4 KiB

Reglas obligatorias de mapeo de resultados

Estas reglas complementan AGENTS.md y AGENTS_STORED_PROCEDURES.md.

Extensión estándar

  • Todo resultado obtenido con IDataReader debe convertirse mediante AppCode/Utilities/DataReaderExtensions.cs.
  • No repetir bloques manuales como Propiedad = Convert.ToInt32(reader["Columna"]) en repositorios o servicios.
  • Resultados admitidos:
T item = reader.ToObject<T>();
List<T> items = reader.ToList<T>();
DataTable table = reader.ToDataTable();
JArray json = reader.ToJsonArray();
  • ToObject<T>() devuelve null cuando el procedimiento no devuelve filas.
  • ToList<T>() devuelve una lista vacía cuando no hay filas; no devuelve null.
  • ToDataTable() devuelve un DataTable vacío cuando no hay filas.
  • ToJsonArray() devuelve un JArray vacío cuando no hay filas.

Operaciones asíncronas

  • Para código nuevo, preferir las versiones asíncronas cuando el proveedor exponga DbCommand y DbDataReader.
  • Métodos disponibles: ToObjectAsync<T>(), ToListAsync<T>(), ToDataTableAsync() y ToJsonArrayAsync().
  • Los métodos asíncronos deben recibir y propagar un CancellationToken cuando la llamada superior disponga de uno.
  • Abrir el lector con ExecuteReaderAsync; no envolver operaciones síncronas de base de datos en Task.Run.
  • Usar ConfigureAwait(false) dentro de infraestructura, repositorios y servicios que no necesiten el contexto de WebForms.
  • Cerrar o desechar el lector antes de leer @ErrorMostrar, @ErrorTipo y @Return.
  • Una página WebForms que espere directamente debe declarar Async="true" y usar RegisterAsyncTask o un evento asíncrono compatible.
  • Mantener los métodos síncronos únicamente para flujos existentes que todavía no se hayan migrado de extremo a extremo.

Ejemplo:

List<UsuarioModel> usuarios;

using (DbDataReader reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false))
{
    usuarios = await reader.ToListAsync<UsuarioModel>(cancellationToken).ConfigureAwait(false);
}

StoredProcedureCommand.EnsureSuccess(command);
return usuarios;

Convención de columnas y propiedades

  • El mapeo se realiza por nombre de columna y propiedad sin distinguir mayúsculas/minúsculas.
  • Los procedimientos deben usar alias para que las columnas coincidan con el modelo.
  • Cuando no sea posible usar el mismo nombre, decorar la propiedad con [Column("NombreColumna")].
  • Las columnas adicionales se ignoran.
  • Las propiedades sin columna conservan su valor predeterminado.
  • DBNull se convierte en null para propiedades anulables o de referencia; para propiedades no anulables conserva el valor predeterminado.
  • Se admiten tipos anulables, enumeraciones, Guid, TimeSpan, DateTimeOffset, booleanos y conversiones primitivas.
  • Una conversión incompatible debe producir una excepción para que DbExecutor la registre; no ocultar errores de contrato entre el PA y el modelo.

Uso correcto con procedimientos almacenados

  • El repositorio crea y configura el comando mediante StoredProcedureCommand.
  • El repositorio abre el lector dentro de using.
  • Debe cerrar o desechar el lector antes de llamar StoredProcedureCommand.EnsureSuccess(command), porque los parámetros OUTPUT se reciben al finalizar el lector.
  • La extensión sólo mapea datos; no abre conexiones, no crea comandos, no captura excepciones y no decide mensajes para el usuario.
  • Páginas ASPX, controles y master pages no deben manejar IDataReader directamente.

Ejemplo para un objeto:

UserModel user;

using (IDataReader reader = command.ExecuteReader())
{
    user = reader.ToObject<UserModel>();
}

StoredProcedureCommand.EnsureSuccess(command);
return user;

Ejemplo para una lista:

List<MenuItemModel> items;

using (IDataReader reader = command.ExecuteReader())
{
    items = reader.ToList<MenuItemModel>();
}

StoredProcedureCommand.EnsureSuccess(command);
return items;

Elección del tipo de resultado

  • Preferir modelos tipados para reglas de negocio, seguridad, usuarios, permisos, menús y módulos nuevos.
  • Usar DataTable sólo para compatibilidad con componentes WebForms o migración de código heredado que realmente lo requiera.
  • Usar JArray únicamente cuando el contrato de salida sea JSON dinámico y no exista un modelo estable.
  • No convertir primero a DataTable para después crear objetos o JSON; mapear directamente desde IDataReader.