← Zurück zum Blog

Record Mark in Business Central – wann sinnvoll, warum und wann nicht?

Wer in Microsoft Dynamics 365 Business Central mit AL entwickelt, stößt früher oder später auf Record.Mark() und Record.MarkedOnly().

Auf den ersten Blick wirkt Record Mark wie eine weitere Möglichkeit, Datensätze zu filtern. Tatsächlich ist das Konzept aber etwas anders: Mit Mark() kann man Datensätze innerhalb einer Record-Instanz gezielt markieren und später mit MarkedOnly() nur noch diese markierten Datensätze verarbeiten.

Das ist besonders interessant, wenn die Auswahl der Datensätze nicht mit einem normalen Filter beschrieben werden kann. Gleichzeitig ist Record Mark kein Werkzeug, das man für jede beliebige Selektion einsetzen sollte.

Die entscheidende Frage lautet deshalb:

Möchte ich Datensätze anhand ihrer Feldwerte filtern – oder möchte ich eine zuvor individuell zusammengestellte Auswahl von Datensätzen weiterverarbeiten?

Was macht Record Mark eigentlich?

Mit Record.Mark(true) wird ein Datensatz markiert. Anschließend kann mit Record.MarkedOnly(true) die Sicht auf die Tabelle auf die zuvor markierten Datensätze eingeschränkt werden.

Ein einfaches Beispiel:

var
    Customer: Record Customer;
begin
    Customer.Get('10000');
    Customer.Mark(true);

    Customer.MarkedOnly(true);

    if Customer.FindSet() then
        repeat
            // Nur markierte Datensätze verarbeiten.
        until Customer.Next() = 0;
end;

Wichtig ist dabei ein Detail, das bei der Verwendung leicht übersehen wird:

Die Markierung ist temporär. Sie wird nicht als Feld in der Datenbank gespeichert und verschwindet mit dem Ende der aktuellen Session. Außerdem gilt eine Markierung für die konkrete Record-Instanz und wird nicht automatisch von allen Record-Variablen desselben Tabellentyps geteilt.

Microsoft beschreibt Mark() entsprechend als temporäre Markierung eines Datensatzes. MarkedOnly() schaltet anschließend eine spezielle Sicht ein, in der nur markierte Datensätze berücksichtigt werden.

Warum kann Record Mark sinnvoll sein?

Der größte Vorteil von Record Mark liegt darin, dass man eine individuelle Auswahl von Datensätzen aufbauen kann.

Das ist etwas anderes als ein klassischer Filter.

Ein Filter beschreibt beispielsweise:

SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
SalesHeader.SetRange("Sell-to Customer No.", CustomerNo);

Hier ist eindeutig definiert:

Verarbeite alle Datensätze, deren Feldwerte diese Bedingungen erfüllen.

Mit Record Mark kann dagegen eine Auswahl entstehen, die beispielsweise aus mehreren unterschiedlichen Verarbeitungsschritten stammt:

if SomeCondition then
    Customer.Mark(true);

if AnotherCondition then
    Customer.Mark(true);

if SpecialCase then
    Customer.Mark(true);

Am Ende können genau diese Datensätze weiterverarbeitet werden.

Das ist besonders praktisch, wenn die Auswahl nicht sinnvoll durch einen einzigen Feldfilter ausgedrückt werden kann.

Ein typischer Anwendungsfall: Datensätze schrittweise auswählen

Stellen wir uns vor, eine Verarbeitung soll Kunden berücksichtigen, die aus mehreren unterschiedlichen Gründen ausgewählt wurden.

Zum Beispiel:

  • Kunden aus einer bestimmten Region
  • zusätzlich Kunden mit offenen Vorgängen
  • zusätzlich einzelne Kunden aus einer manuellen Auswahl
  • aber nicht Kunden, die bereits verarbeitet wurden

Eine solche Auswahl kann mit mehreren Bedingungen aufgebaut werden.

Customer.Reset();

if Customer.FindSet() then
    repeat
        if Customer."Country/Region Code" = 'DE' then
            Customer.Mark(true);

        if HasOpenProcess(Customer) then
            Customer.Mark(true);
    until Customer.Next() = 0;

Customer.MarkedOnly(true);

if Customer.FindSet() then
    repeat
        ProcessCustomer(Customer);
    until Customer.Next() = 0;

Hier wird Record Mark nicht als Ersatz für einen normalen Filter verwendet.

Stattdessen dient die Markierung als Zwischenergebnis einer komplexeren Auswahl.

Genau dafür kann das Konzept sehr nützlich sein.

Record Mark und Benutzerauswahl

Ein besonders interessanter Anwendungsfall ist die Auswahl von Datensätzen durch den Benutzer auf einer Business-Central-Seite.

Dafür gibt es beispielsweise:

CurrPage.SetSelectionFilter(Customer);

Page.SetSelectionFilter() übernimmt die vom Benutzer ausgewählten Datensätze, markiert diese und setzt den übergebenen Record auf „marked only“.

Das ist ein wichtiger Unterschied zu einer normalen Filtereingabe:

Der Benutzer kann in einer Liste beispielsweise mehrere konkrete Datensätze auswählen, auch wenn diese keine gemeinsame einfache Filterbedingung haben.

Beispielsweise:

Kunde 10000
Kunde 10005
Kunde 10017
Kunde 10042

Diese vier Datensätze können gemeinsam ausgewählt und anschließend verarbeitet werden.

Microsoft weist darauf hin, dass SetSelectionFilter() bei mehreren ausgewählten Datensätzen die ausgewählten Records markiert und den Filter „marked only“ setzt. Bei einer Auswahl des gesamten Datensatzbestands werden dagegen keine Marks verwendet.

Das macht SetSelectionFilter() für Aktionen auf List Pages besonders interessant.

Wann Record Mark keine gute Idee ist

Record Mark ist mächtig, aber nicht automatisch die beste Lösung.

1. Wenn ein normaler Filter ausreicht

Wenn die fachliche Bedingung einfach lautet:

Alle Verkaufszeilen mit Menge größer als 0.

dann sollte man daraus keinen Markierungsprozess bauen.

Ein normaler Filter ist hier wesentlich verständlicher:

SalesLine.SetFilter(Quantity, '>0');

Die Bedingung ist direkt am Record sichtbar und kann von anderen Entwicklern leichter nachvollzogen werden.

Faustregel:

Wenn sich die Auswahl sauber über SetRange() oder SetFilter() ausdrücken lässt, ist ein normaler Filter meistens die klarere Lösung.

2. Wenn die Auswahl dauerhaft gespeichert werden soll

Ein Mark ist kein Datenbankstatus.

Wenn die Information fachlich relevant ist und beispielsweise auch morgen noch vorhanden sein muss, gehört sie nicht in Record.Mark().

Dafür braucht es beispielsweise:

  • ein echtes Tabellenfeld
  • eine eigene Zuordnungstabelle
  • einen Verarbeitungsstatus
  • oder eine andere persistente Datenstruktur

Record Mark ist für eine temporäre Verarbeitungsauswahl gedacht – nicht als Ersatz für Datenhaltung.

3. Wenn mehrere Verarbeitungsschritte voneinander getrennt sind

Da Marks an die jeweilige Record-Instanz und Session gebunden sind, sollte man genau darauf achten, welche Record-Variable die Markierungen enthält.

Das kann insbesondere bei umfangreicherem Code schnell unübersichtlich werden:

Customer.Mark(true);

// ...

Customer2.MarkedOnly(true);

Hier sollte man nicht automatisch davon ausgehen, dass Customer2 dieselbe Markierungssicht besitzt.

Die Dokumentation von Microsoft weist ausdrücklich darauf hin, dass die Markierung für die jeweilige Record-Instanz gilt und nicht automatisch zwischen allen Variablen desselben Record-Typs geteilt wird.

4. Wenn eigentlich eine Datenbankabfrage gemeint ist

Ein weiterer wichtiger Punkt:

Record Mark sollte nicht dazu verwendet werden, eine normale Datenbankselektion unnötig kompliziert nachzubauen.

Wenn die Auswahl fachlich über Felder beschrieben werden kann, ist ein Filter häufig die passendere Abstraktion:

Customer.SetRange("Blocked", Customer.Blocked::" ");
Customer.SetFilter("Balance (LCY)", '>0');

Statt zunächst zahlreiche Datensätze zu durchlaufen, zu markieren und anschließend wieder nur die Marks zu verarbeiten, sollte man prüfen, ob die Datenmenge direkt über die vorhandenen Filterbedingungen eingeschränkt werden kann.

Das macht den Code häufig einfacher und die Absicht deutlich sichtbarer.

Was passiert mit den Marks?

Marks sind temporär. Deshalb sollte man sich bewusst machen, wann sie gesetzt und wann sie nicht mehr benötigt werden.

Mit:

Record.ClearMarks();

können alle Marks der entsprechenden Record-Instanz entfernt werden.

Das ist besonders dann sinnvoll, wenn dieselbe Record-Variable anschließend für eine neue, unabhängige Auswahl verwendet werden soll.

Beispiel:

Customer.ClearMarks();

// Neue Auswahl aufbauen.
if Customer.FindSet() then
    repeat
        if ShouldProcess(Customer) then
            Customer.Mark(true);
    until Customer.Next() = 0;

Customer.MarkedOnly(true);

Noch besser ist es allerdings, Record-Variablen und deren Lebenszyklus so zu strukturieren, dass bereits aus dem Code klar hervorgeht, wann eine Markierung aufgebaut und wann sie verarbeitet wird.

Record Mark oder Filter?

Die beiden Ansätze erfüllen unterschiedliche Aufgaben.

SituationGeeigneter Ansatz
Alle Datensätze mit einem bestimmten FeldwertSetRange() / SetFilter()
Datensätze anhand mehrerer klarer Feldbedingungen auswählenFilter
Benutzer wählt mehrere konkrete Datensätze aus einer ListeSetSelectionFilter() / Marks
Auswahl entsteht schrittweise aus unterschiedlichen BedingungenMarks können sinnvoll sein
Auswahl muss dauerhaft gespeichert werdenTabellenfeld / eigene Datenstruktur
Datensatzstatus soll über Sessions hinweg erhalten bleibenPersistente Datenhaltung
Einfache DatenbankselektionFilter
Individuelle temporäre VerarbeitungsauswahlMarks

Der wichtigste Unterschied lässt sich damit sehr einfach zusammenfassen:

Filter beschreiben, welche Datensätze fachlich passen. Marks beschreiben, welche Datensätze für eine konkrete Verarbeitung ausgewählt wurden.

Praxiserfahrungen aus der Entwicklung

In der Praxis lohnt es sich deshalb, vor der Verwendung von Mark() zunächst die Frage zu stellen:

Was ist eigentlich die fachliche Bedeutung meiner Auswahl?

Wenn die Antwort lautet:

„Alle Datensätze, die Bedingung X erfüllen.“

ist ein Filter meistens naheliegend.

Wenn die Antwort dagegen lautet:

„Diese konkreten Datensätze wurden im vorherigen Schritt ausgewählt und sollen jetzt gemeinsam verarbeitet werden.“

kann Record Mark genau das richtige Werkzeug sein.

Besonders bei Aktionen auf Listen ist das Konzept stark: Der Benutzer trifft eine konkrete Auswahl und der Entwickler kann anschließend genau diese Auswahl weiterverarbeiten, ohne dafür eine künstliche Filterlogik aufbauen zu müssen.

💡 Merksatz: Record Mark ist weniger ein „besserer Filter“ als vielmehr eine temporäre Auswahlmenge für die weitere Verarbeitung.

Vorteile auf einen Blick

  • Individuelle Auswahl: Auch Datensätze ohne gemeinsame einfache Filterbedingung können gemeinsam verarbeitet werden.
  • Temporär: Marks müssen nicht als zusätzliche Datenbankfelder gespeichert werden.
  • Gut für Benutzeraktionen: Besonders in Kombination mit SetSelectionFilter() können konkrete Listenauswahlen verarbeitet werden.
  • Flexible Verarbeitung: Auswahlkriterien können aus mehreren vorherigen Verarbeitungsschritten entstehen.
  • Klare Trennung: Die Auswahl kann von der eigentlichen Verarbeitung getrennt werden.

Fazit

Record.Mark() ist in Business Central ein nützliches Werkzeug – aber vor allem für den richtigen Anwendungsfall.

Wer einfach Datensätze anhand ihrer Feldwerte einschränken möchte, sollte in der Regel zuerst an SetRange() und SetFilter() denken.

Record Mark spielt seine Stärke dort aus, wo eine konkrete, temporäre Auswahl von Datensätzen aufgebaut und anschließend weiterverarbeitet werden soll.

Besonders interessant ist die Kombination mit Page.SetSelectionFilter(): Der Benutzer wählt Datensätze in einer Liste aus und der Entwickler erhält genau diese Auswahl für die weitere Verarbeitung.

Die wichtigste Regel lautet daher:

Nicht markieren, weil man markieren kann. Markieren, wenn wirklich eine konkrete Auswahlmenge benötigt wird.

Ausblick

Gerade bei Business-Central-Entwicklungen entscheidet häufig nicht die einzelne AL-Methode über eine gute Lösung, sondern die Frage, welche Datenmenge an welcher Stelle des Prozesses eigentlich benötigt wird.

Wer Filter, Keys, Record Selection und Marks bewusst einsetzt, kann seine AL-Logik deutlich nachvollziehbarer strukturieren – und vermeidet gleichzeitig unnötig komplizierte Auswahlmechanismen.

Weiterführend: