4.4 KiB
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
IDataReaderdebe convertirse medianteAppCode/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>()devuelvenullcuando el procedimiento no devuelve filas.ToList<T>()devuelve una lista vacía cuando no hay filas; no devuelvenull.ToDataTable()devuelve unDataTablevacío cuando no hay filas.ToJsonArray()devuelve unJArrayvacío cuando no hay filas.
Operaciones asíncronas
- Para código nuevo, preferir las versiones asíncronas cuando el proveedor exponga
DbCommandyDbDataReader. - Métodos disponibles:
ToObjectAsync<T>(),ToListAsync<T>(),ToDataTableAsync()yToJsonArrayAsync(). - Los métodos asíncronos deben recibir y propagar un
CancellationTokencuando la llamada superior disponga de uno. - Abrir el lector con
ExecuteReaderAsync; no envolver operaciones síncronas de base de datos enTask.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,@ErrorTipoy@Return. - Una página WebForms que espere directamente debe declarar
Async="true"y usarRegisterAsyncTasko 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.
DBNullse convierte ennullpara 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
DbExecutorla 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
IDataReaderdirectamente.
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
DataTablesó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
DataTablepara después crear objetos o JSON; mapear directamente desdeIDataReader.