Tipos de Tabla Avanzados
En Business Central, no todas las tablas tienen el mismo rol ni el mismo ciclo de vida. Más allá de las tablas maestras o de configuración, existen categorías especializadas que responden a necesidades concretas del sistema: tablas que capturan un proceso en curso, tablas que guardan el resultado permanente de ese proceso y tablas cuyo acceso está controlado por el propio sistema. Entender estas categorías es esencial para diseñar extensiones coherentes con la arquitectura de BC.
1. Tablas de Registro y Documento Publicado
¿Cuál es la diferencia?
Business Central separa el proceso de introducción de datos del resultado contable definitivo en dos tablas distintas. La tabla de cabecera/línea de documento actúa como borrador editable; cuando el usuario contabiliza (Post), BC mueve y transforma esos datos a una tabla de documento publicado que ya no se puede modificar.
| Tipo | Ejemplo real en BC | ¿Se puede editar? | ¿Se puede borrar? |
|---|---|---|---|
| Documento (borrador) | Sales Header / Sales Line |
Sí, hasta que se contabiliza | Sí (con permisos) |
| Documento publicado | Sales Invoice Header / Sales Invoice Line |
No (solo lectura) | No (registro contable) |
| Entrada de registro (Ledger) | Cust. Ledger Entry, G/L Entry |
No | No |
El flujo de contabilización
El proceso siempre sigue la misma secuencia: el usuario crea y edita el documento borrador, luego ejecuta la acción Post (contabilizar). En ese momento BC valida los datos, genera los movimientos de libro mayor y crea el documento publicado. Los datos del borrador se eliminan o archivan según la configuración.
// Tabla de documento borrador (editable)
table 36 "Sales Header"
{
DataClassification = CustomerContent;
Caption = 'Sales Header';
fields
{
field(1; "Document Type"; Enum "Sales Document Type") { }
field(3; "No."; Code[20]) { }
field(2; "Sell-to Customer No."; Code[20])
{
TableRelation = Customer;
}
}
// La tabla borrador PERMITE triggers de escritura
trigger OnInsert()
begin
// Asignar número de serie, fecha, etc.
end;
}
// Tabla de documento publicado (solo lectura en la práctica)
table 112 "Sales Invoice Header"
{
DataClassification = CustomerContent;
Caption = 'Sales Invoice Header';
// Mismos campos que Sales Header, pero ya no se editan
fields
{
field(3; "No."; Code[20]) { }
field(2; "Sell-to Customer No."; Code[20]) { }
field(20; "Posting Date"; Date) { }
}
}
¿Cómo lo aplico en mis extensiones?
Cuando amplíes un documento de BC con campos propios, debes añadir el campo en ambas tablas: en el borrador y en el publicado. De lo contrario, el dato desaparecerá tras la contabilización. El codeunit de posting se encarga de copiar los valores del borrador al publicado.
// TableExtension sobre el borrador
tableextension 50100 "Sales Header Ext." extends "Sales Header"
{
fields
{
field(50100; "Motivo Descuento"; Text[100]) { }
}
}
// TableExtension TAMBIÉN sobre el publicado
tableextension 50101 "Sales Inv. Header Ext." extends "Sales Invoice Header"
{
fields
{
field(50100; "Motivo Descuento"; Text[100]) { }
}
}
💡 Regla práctica
- Si el campo que añades tiene valor de negocio (se necesita en facturas impresas, informes o auditoría), va en ambas tablas.
- Si solo sirve durante la edición del borrador (ej. un flag temporal de validación), solo va en el borrador.
- El número de campo (
50100) debe coincidir en ambas extensiones para que el codeunit de posting lo copie sin código adicional.
2. Tablas por Nivel de Acceso: Modificable, Sistema y Solo Lectura
Business Central clasifica sus tablas internas según quién puede escribir en ellas y bajo qué circunstancias. Esta clasificación no siempre aparece como una propiedad explícita, sino que se deduce de la combinación de propiedades, permisos y diseño de la tabla.
| Categoría | Descripción | Ejemplos | ¿Extensible? |
|---|---|---|---|
| Totalmente modificable | El usuario puede crear, editar y borrar registros libremente desde la UI. | Customer, Item, tablas maestras propias |
Sí |
| Contenido modificable | Se puede editar desde la UI pero con restricciones (ej. no borrar si hay movimientos). | Sales Header, Purchase Header |
Sí |
| Sistema / Virtual | Tablas internas de BC que no almacenan datos en SQL. Solo existen en memoria o las gestiona el runtime. | Integer, Date, Session |
No |
| Solo lectura | Se generan automáticamente por procesos de posting. El usuario nunca escribe en ellas directamente. | G/L Entry, Cust. Ledger Entry, Sales Invoice Header |
Sí (TableExtension), pero no se insertan registros manualmente |
Tablas virtuales del sistema
Las tablas virtuales son un caso especial. BC las usa internamente para ciertas operaciones
y no corresponden a una tabla física en la base de datos SQL. La más usada en código AL es
Integer, que se emplea para generar bucles o listas de números sin necesidad
de una tabla real.
// Uso de la tabla virtual "Integer" para iterar sin tabla real
var
IntRec: Record Integer;
begin
IntRec.SetRange(Number, 1, 10);
if IntRec.FindSet() then
repeat
Message('Iteración número: %1', IntRec.Number);
until IntRec.Next() = 0;
end;
Propiedad TableType
En AL, la propiedad TableType de una tabla permite declarar explícitamente
su comportamiento especial. Si no se indica, el valor por defecto es Normal.
table 50200 "Mi Tabla Temporal"
{
// TableType = Temporary indica que esta tabla solo existe en memoria
// durante la ejecución. No persiste en la base de datos.
TableType = Temporary;
fields
{
field(1; "Entry No."; Integer) { }
field(2; "Descripcion"; Text[100]) { }
}
keys
{
key(PK; "Entry No.") { Clustered = true; }
}
}
| Valor de TableType | Significado |
|---|---|
Normal |
Tabla estándar con persistencia en SQL (valor por defecto). |
Temporary |
Solo existe en memoria durante la sesión. Útil para buffers intermedios. |
CRM |
Tabla mapeada a Dynamics 365 CRM / Dataverse. |
ExternalSQL |
Tabla mapeada a una fuente SQL externa. |
⚠️ Atención con las tablas de solo lectura
- Nunca intentes insertar registros directamente en tablas de tipo Ledger Entry o Invoice Header desde tu código. BC lo bloqueará o corromperá la integridad contable.
- Si necesitas añadir datos relacionados con una entrada contable, crea tu propia tabla auxiliar con una
TableRelationa la entrada correspondiente. - Las tablas virtuales (
Integer,Date) no se pueden extender conTableExtension.
💡 Resumen rápido
- Borrador → Publicado: todo campo de negocio que añadas al borrador debe ir también en el publicado.
- Tablas del sistema: se usan pero no se extienden ni se modifican.
- Solo lectura: se extienden para añadir campos pero nunca se insertan registros manualmente.
- TableType = Temporary: útil para manejar datos intermedios sin tocar la base de datos.