134 lines
6.8 KiB
Markdown
134 lines
6.8 KiB
Markdown
# Reglas obligatorias de procedimientos almacenados
|
|
|
|
Estas reglas complementan `AGENTS.md` y son obligatorias para toda consulta nueva o modificada en la aplicación.
|
|
|
|
## Acceso a datos
|
|
|
|
- Todas las lecturas y escrituras de la aplicación deben usar procedimientos almacenados.
|
|
- No escribir `SELECT`, `INSERT`, `UPDATE`, `DELETE` ni `MERGE` directamente en C# dentro de repositorios, servicios, páginas, controles o la master page.
|
|
- Los repositorios deben usar `CommandType.StoredProcedure`.
|
|
- Todos los valores proporcionados por la aplicación deben enviarse como parámetros.
|
|
- Nunca concatenar entrada del usuario en SQL.
|
|
|
|
## Nombres
|
|
|
|
- Usar el formato `PA_<Tipo>_<Entidad><Accion>`.
|
|
- `PA` significa procedimiento almacenado.
|
|
- `<Tipo>` identifica el grupo funcional: `Sis`, `Tra`, `Vta`, `Conta`, `Clientes`, `Fraccionamientos`, etcétera.
|
|
- `<Entidad>` identifica el objeto y `<Accion>` describe claramente la operación; por ejemplo `Add`, `Update`, `List`, `Activate`, `Deactivate` o `Delete`.
|
|
- Ejemplos: `PA_Sis_UsuarioAdd`, `PA_Sis_UsuarioUpdate`, `PA_Sis_UsuarioList`, `PA_Sis_UsuarioActivate`, `PA_Sis_UsuarioDeactivate` y `PA_Sis_UsuarioDelete`.
|
|
|
|
## Procedimientos de tareas programadas
|
|
|
|
- Los procedimientos de tareas programadas deben usar el prefijo `PA_Job_` y nombres descriptivos en español, por ejemplo `PA_Job_VerificaVigencias`.
|
|
- Ejecutarlos mediante el programador externo; no invocarlos desde cargas de página, consultas del tablero ni peticiones web.
|
|
- Documentar su periodicidad, hora y zona horaria. La verificación de vigencias se programa diariamente a las 03:00, hora de Hermosillo.
|
|
- El recálculo puntual después de guardar cambios permanece en su servicio y no debe disparar la revisión global de vigencias.
|
|
- Preparar el SQL no autoriza su ejecución ni la activación del trabajo; requieren confirmación explícita conforme a `AGENTS.md`.
|
|
|
|
## Formato de JOIN
|
|
|
|
- Mantener cada `JOIN` y su condición `ON` en la misma línea cuando la condición sea simple o pueda continuarse de forma legible en las líneas siguientes.
|
|
- No separar `ON` en una línea independiente únicamente por estilo.
|
|
- Evitar subconsultas con `SELECT` directamente dentro de un `JOIN`. Cuando la consulta relacionada sea compleja, preferir un CTE con `WITH` y realizar el `JOIN` contra ese CTE.
|
|
- Una condición extensa del `ON` puede continuar en líneas adicionales, alineando cada `AND` para conservar la legibilidad.
|
|
|
|
## Parámetros y resultado obligatorios
|
|
|
|
Todos los procedimientos deben declarar:
|
|
|
|
```sql
|
|
@CveUsuarioEjecuta int,
|
|
@ErrorMostrar varchar(max) OUTPUT,
|
|
@ErrorTipo int OUTPUT,
|
|
@Return bit OUTPUT
|
|
```
|
|
|
|
- `@CveUsuarioEjecuta` identifica al usuario autenticado que ejecuta la operación.
|
|
- Al inicio, establecer `@ErrorMostrar = NULL`, `@ErrorTipo = 0` y `@Return = 0`.
|
|
- Establecer `@Return = 1` únicamente cuando la operación termine correctamente.
|
|
- `@ErrorTipo = 0`: sin error ni advertencia.
|
|
- `@ErrorTipo = 1`: error.
|
|
- `@ErrorTipo = 2`: advertencia.
|
|
- `@ErrorMostrar` contiene el mensaje amigable en español que puede mostrarse al usuario.
|
|
- No devolver contraseñas, hashes, cadenas de conexión, SQL, stack traces ni detalles internos mediante `@ErrorMostrar`.
|
|
- Los procedimientos de consulta pueden devolver un result set, pero también deben poblar los parámetros comunes.
|
|
- El repositorio debe convertir los parámetros de salida en un modelo de resultado como `DbResult<T>`.
|
|
|
|
## Control de errores
|
|
|
|
- Usar `SET NOCOUNT ON` y `TRY/CATCH` en todos los procedimientos.
|
|
- Los procedimientos no deben usar `SET XACT_ABORT ON`, `BEGIN TRANSACTION`, `COMMIT TRANSACTION`, `ROLLBACK TRANSACTION` ni modificar una transacción recibida.
|
|
- La transacción pertenece a la capa de servicio en C#, que debe usar `TransactionLogic` dentro de `using` al coordinar las llamadas a repositorios.
|
|
- El servicio llama `Commit()` solamente cuando todas las operaciones requeridas terminan correctamente. Un fallo, excepción o salida sin `Commit()` debe permitir que `Dispose()` revierta la transacción ambiental.
|
|
- Una validación fallida debe establecer los parámetros de salida y ejecutar `RETURN`; no debe continuar la mutación.
|
|
- Para validar existencia, usar normalmente `EXISTS` en lugar de `COUNT(*)`.
|
|
- En `CATCH`, generar un mensaje técnico separado con `ERROR_NUMBER()`, `ERROR_PROCEDURE()`, `ERROR_LINE()` y `ERROR_MESSAGE()` para el log.
|
|
- El mensaje técnico puede notificarse con severidad informativa para que el ejecutor lo registre, pero nunca debe mostrarse directamente al usuario.
|
|
|
|
## Borrado físico
|
|
|
|
- La base de datos no utiliza las columnas `Borrado` ni `FechaBorrado`; no deben agregarse a tablas, modelos, consultas ni procedimientos nuevos.
|
|
- Las operaciones de eliminación deben usar `DELETE` físico dentro de un procedimiento almacenado.
|
|
- Antes de eliminar, validar las relaciones que deban conservarse. Si existen dependencias que impiden la operación, devolver una advertencia controlada con `@ErrorTipo = 2` y un mensaje claro.
|
|
- Las eliminaciones de una entidad con hijos propios deben ejecutarse en orden, desde los hijos hasta el padre. El servicio que invoque el procedimiento debe envolver la operación en una transacción de aplicación.
|
|
- No deshabilitar constraints ni eliminar información relacionada que pertenezca a otro proceso únicamente para permitir el `DELETE`.
|
|
- Las páginas ASPX continúan llamando contratos y servicios; nunca deben ejecutar `DELETE` directamente.
|
|
|
|
## Plantilla requerida
|
|
|
|
```sql
|
|
CREATE OR ALTER PROCEDURE [dbo].[PA_Sis_RolAdd]
|
|
@Rol varchar(50),
|
|
@CveUsuarioEjecuta int,
|
|
@ErrorMostrar varchar(max) OUTPUT,
|
|
@ErrorTipo int OUTPUT,
|
|
@Return bit OUTPUT
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
SELECT
|
|
@ErrorMostrar = NULL,
|
|
@ErrorTipo = 0,
|
|
@Return = 0;
|
|
|
|
BEGIN TRY
|
|
IF EXISTS
|
|
(
|
|
SELECT 1
|
|
FROM dbo.Sis_Roles
|
|
WHERE NombreRol = @Rol
|
|
)
|
|
BEGIN
|
|
SET @ErrorMostrar = CONCAT('El rol ''', @Rol, ''' ya se encuentra registrado.');
|
|
SET @ErrorTipo = 2;
|
|
RETURN;
|
|
END;
|
|
|
|
INSERT INTO dbo.Sis_Roles
|
|
(NombreRol, Activo, FechaCreacion)
|
|
VALUES
|
|
(@Rol, 1, SYSDATETIME());
|
|
|
|
SET @Return = 1;
|
|
END TRY
|
|
BEGIN CATCH
|
|
SET @ErrorMostrar = 'Ocurrió un error al agregar el rol; favor de contactar a Sistemas.';
|
|
SET @ErrorTipo = 1;
|
|
SET @Return = 0;
|
|
|
|
DECLARE @ErrorTecnico nvarchar(2048) = CONCAT(
|
|
'Número: ', ERROR_NUMBER(),
|
|
'; Procedimiento: ', COALESCE(ERROR_PROCEDURE(), 'PA_Sis_RolAdd'),
|
|
'; Línea: ', ERROR_LINE(),
|
|
'; Detalle: ', ERROR_MESSAGE()
|
|
);
|
|
|
|
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
|
|
END CATCH;
|
|
END;
|
|
GO
|
|
```
|
|
|
|
Aunque un procedimiento ejecute varias escrituras, no debe administrar la transacción. La atomicidad se define en el servicio que coordina los repositorios.
|