Dif. 5/10

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
Contenido modificable Se puede editar desde la UI pero con restricciones (ej. no borrar si hay movimientos). Sales Header, Purchase Header
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 TableRelation a la entrada correspondiente.
  • Las tablas virtuales (Integer, Date) no se pueden extender con TableExtension.

💡 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.
← Volver a Teoría