Saltearse al contenido

Manipular datos

Para recuperar datos de la base de datos, puede usar las funciones de acceso a datos.

Puede usar las siguientes funciones de acceso a datos para obtener registros:

  • Get
  • Find, FindFirst, FindLast
  • Next
  • IsEmpty

La función Get recupera un registro basado en la clave principal. Si la tabla tiene una clave principal de un campo, debe proporcionarle un parámetro a la función Get.

var
customer: Record Customer;
begin
customer.Get('30000');
if customer.Get('10000') then
Message('%1', customer)
else
Error('Not found');
end;

La función Find tiene dos funciones derivadas: FindFirst y FindLast. En algún código estándar, se siguen utilizando las funciones Find('-') y Find('+'). Estas funciones se utilizaron en versiones anteriores de Business Central.

La función Find('-') le solicita SELECT a SQL Server y recupera el primer registro de Business Central. Por tanto, este proceso genera un rendimiento deficiente. Es mejor utilizar las funciones FindFirst y FindLast.

var
customer: Record Customer;
begin
customer.Find('-');
// SELECT * FROM Customer
Message('%1', customer.Name);
customer.Find('+');
// SELECT * FROM Customer Order By No. Desc
Message('%1', customer.Name);
customer.FindFirst();
// SELECT TOP 1 * FROM Customer
Message('%1', customer.Name);
customer.FindLast();
// SELECT TOP 1 * FROM Customer Order By No. Desc
Message('%1', customer.Name);

Para recuperar todos los registros (o un conjunto filtrado de registros), puede usar la función FindSet.

customer.FindSet();
// SELECT * FROM Customer

La instrucción Next se utiliza para obtener el siguiente registro de un conjunto de registros. Por lo general, la instrucción Next se usaría en una instrucción repeat until

customer.FindSet();
// SELECT * FROM Customer
repeat
// process record
Message(customer.Name);
until customer.Next() = 0;

Si desea comprobar si existe un registro, pero no desea recuperarlo, la mejor opción es usar la función IsEmpty.

Para ordenar registros, use la función SetCurrentKey, donde puede especificar los campos por los que desea ordenar.

var
customer: Record Customer;
begin
customer.SetCurrentKey(City);
customer.FindFirst();
Message('%1', customer);

puede especificar un valor inicial y final para un campo específico. Sin embargo, no puede usar la función SetRange para buscar registros donde el valor del campo sea mayor o menor que un valor específico.

SetRange(Field, [FromValue], [ToValue])
customer.SetRange("No.", '10000', '40000');
customer.FindSet();
repeat
Message('%1', customer);
until customer.Next() = 0;

La función SetFilter acepta un valor de cadena donde puede especificar las condiciones de filtrado; por ejemplo:

  • >
  • <
  • < >
  • <=
  • >=
  • '*'
  • .. (intervalo)
  • & (y)
  • | (o) y más en esta condición de filtro
SetFilter(Field, String, [Value1], [Value2], …)
customer.SetFilter("No.", '> 10000 & <> 20000');
value1 := '10000';
value2 := '20000';
customer.SetFilter("No.", '>%1&<>%2', value1, value2);
customer.SetRange("No.", '10000', '90000');
customer.SetFilter(City, '@B*');
customer.SetFilter("Country/Region Code", 'B*');
customer.FindSet();
repeat
Message('%1', customer);
until customer.Next() = 0;
customer.SetFilter("No.", '10000|20000|30000');

Con frecuencia, se les pedirá a los desarrolladores que modifiquen los datos en la base de datos mediante el código AL.

Las siguientes instrucciones permiten la modificación de datos:

  • Insert
  • Modify y ModifyAll
  • Delete y DeleteAll

La instrucción Insert se utiliza para agregar nuevos registros a la base de datos. Antes de poder insertar datos, debe establecer los valores para cada campo que desea almacenar. 

var
customer: Record Customer;
begin
customer.Init();
customer."No." := '4711';
customer.Name := 'John Doe';
customer.Insert(true);

Aunque el desencadenador OnInsert no se ejecuta de forma predeterminada, los eventos OnBeforeInsert u OnAfterInsert siempre se ejecutan.

customer.Get('4711');
customer.Name := 'Richard Roe';
customer.Modify();

Si desea actualizar varios registros simultáneamente, puede usar la función ModifyAll. La función ModifyAll acepta el parámetro RunTrigger como el tercer parámetro de la función.

customer.SetRange("Salesperson Code", 'PS');
customer.ModifyAll("Salesperson Code", 'JR');

Las funciones Modify y ModifyAll no le piden confirmación; la modificación se ejecuta sin previo aviso.

Sección titulada «Las funciones Modify y ModifyAll no le piden confirmación; la modificación se ejecuta sin previo aviso.»

Instrucciones Delete y DeleteAll

Al igual que con la función Modify, necesita recuperar un registro de la base de datos antes de poder eliminar un registro. Las funciones Delete y DeleteAll aceptan el parámetro RunTrigger.

customer.Get('4711');
customer.Delete(true);
customer.SetRange("Salesperson Code", 'PS');
customer.DeleteAll();

Las funciones Delete y DeleteAll no le piden confirmación; la eliminación ocurre sin previo aviso.

Instrucciones CalcFields y SetAutoCalcfields

Sección titulada «Instrucciones CalcFields y SetAutoCalcfields»

Instrucciones CalcFields y SetAutoCalcfields

customer.SetRange("Date Filter", 0D, Today());
// Using CALCFIELDS
if customer.FindSet() then
repeat
customer.CalcFields(Balance, "Net Change");
// Do some additional processing
until customer.Next() = 0;

Si siempre quiere calcular determinados FlowFields (dentro del ámbito de la función), puede usar la función SetAutoCalcFields.

customer.SetAutoCalcFields(Balance, "Net Change");
if customer.FindSet() then
repeat
// Do some additional processing
until customer.Next() = 0;

La función CalcSums se usa para calcular un total para un campo específico, en función de los filtros del conjunto de datos.

salesInvoiceHeader.SetCurrentKey("Bill-to Customer No.");
salesInvoiceHeader.SetRange("Bill-to Customer No.", '10000', '50000');
salesInvoiceHeader.SetRange("Document Date", 0D, Today());
salesInvoiceHeader.CalcSums(Amount);
Message('The total is %1', salesInvoiceHeader.Amount);

La función FieldError detiene la implementación del código, lo que causa un error en tiempo de ejecución y crea un mensaje de error para un campo específico. El campo muestra un borde rojo, lo que indica que se ha producido un error con el valor de este campo.

if item."Unit Price" < 10 then
item.FieldError("Unit Price", 'must be greater than 10');

La mejor estrategia es comenzar usando el comando Init en el registro. Esta acción inicializa todos los campos en el registro.

customer.Init();
customer.Name := 'John Doe';
customer."E-Mail" := 'john.doe@contoso.com';
customer.Insert(true);

Con la función TestField, puede comprobar si un campo tiene un valor o está en blanco. Si el campo está vacío, la función TestField genera un error en tiempo de ejecución.

customer.TestField("Salesperson Code");
customer."Salesperson Code" := 'DK';
customer.TestField("Salesperson Code", 'ZX');

Al asignar un valor a un campo, el desencadenador OnValidate de ese campo no se ejecuta. Si quiere ejecutar el desencadenador OnValidate, use la función Validate.

Customer."Phone No." := '1234567891234'
customer.Validate("Phone No.");

Nivel de Aislamiento (Investigar sobre este tema)

Sección titulada «Nivel de Aislamiento (Investigar sobre este tema)»
local procedure CurrentBehavior()
var
cust: Record Customer;
otherCust: Record Customer;
curr: Record Currency;
begin
cust.FindFirst(); // READUNCOMMITTED
// Heighten isolation level for Customer table.
cust.LockTable();
cust.FindLast(); // UPDLOCK
// Also impacts other instances of same table.
otherCust.FindSet(); // UPDLOCK
// But does not impact other tables.
curr.Find(); // READUNCOMMITTED
end;

La siguiente lista describe los diferentes niveles de aislamiento del tipo de opción IsolationLevel que puede aplicar:

  • Predeterminado
    • Sigue el estado de la transacción. Equivale a no usar el aislamiento de lectura.
  • ReadUncommitted
    • Permite lecturas sucias, lo que significa que puede leer filas que han sido modificadas por otras transacciones, pero que aún no han sido confirmadas. No acepta bloqueos e ignora los bloqueos de otras transacciones.
  • ReadCommitted
    • Solo permite lecturas en datos confirmados; es decir, no puede leer datos que hayan sido modificados por otras transacciones, pero que aún no hayan sido confirmadas. Sin embargo, no garantiza que las filas leídas se mantengan uniformes durante toda la transacción.
  • RepeatableRead
    • Garantiza que todas las lecturas sean estables manteniendo los bloqueos compartidos durante toda la transacción. La transacción no puede leer datos que hayan sido modificados, pero que aún no hayan sido confirmados por otras transacciones, y ninguna otra transacción puede modificar datos que hayan sido leídos por la transacción actual hasta que esta finalice.
  • UpdLock
    • Lee para actualizar e impide que otros lean con la misma intención.