✏️ Explanatory Question

What is a Number Sequence in Dynamics 365 Finance & Operations? Explain how one is set up, the difference between continuous and non-continuous sequences, and how you consume a number sequence in X++ using the NumberSeq class.

👁 8 Views
📘 Detailed Answer
🟢 Easy
💡

Answer with Explanation

D365 F&O • X++ INTERVIEW

Number Sequences in Dynamics 365 Finance & Operations

Question 13 — Generating unique record IDs: setup, the NumberSeq class, and continuous vs. non-continuous.

Interview Question

What is a Number Sequence in Dynamics 365 Finance & Operations? Explain how one is set up, the difference between continuous and non-continuous sequences, and how you consume a number sequence in X++ using the NumberSeq class.

Model Answer (Short)

A number sequence is the framework that generates unique, formatted identifiers for records — such as sales order IDs, invoice numbers or custom document numbers. Setup involves an EDT that represents the ID, a number sequence reference registered through the NumberSeqModuleXxx class (via the loadModule method), and a number sequence code configured in the setup wizard or parameter form. In code you consume it with the NumberSeq class — typically NumberSeq::newGetNum(...) to fetch the next value. A continuous sequence guarantees no gaps (numbers can be recovered if a transaction is aborted), whereas a non-continuous sequence is faster but may leave gaps.

Detailed Explanation

Setup Steps

  • Create an EDT for the identifier (e.g. based on a string type) — this is what the sequence populates.
  • Extend the module's NumberSeqModule... class and register the reference in loadModule() using parmReferenceHelp, parmWizardIsContinuous and parmWizardIsManual.
  • Run the number sequence setup wizard (or configure manually) to create the number sequence code and assign a format/segment.
  • Reference the number sequence in the relevant parameters form so it can be resolved at runtime.

Continuous vs. Non-continuous

  • Continuous — no gaps allowed. If a transaction is cancelled, the number is returned to the pool via a cleanup process. Slower because it locks to preserve order; required where legal/audit numbering demands no gaps.
  • Non-continuous — allows gaps; numbers are pre-allocated in blocks for performance. Preferred where gaps are acceptable (better throughput and fewer locks).
RULE OF THUMB
No gaps / audit = Continuous  •  Performance = Non-continuous

Prerequisites (Rule 5)

  • Visual Studio with the Dynamics 365 developer tools.
  • A custom model / package for your objects.
  • An EDT for the identifier field.
  • A registered number sequence reference and a configured number sequence code.

Code Example — Registering a reference (loadModule)

// Inside a class extending NumberSeqModule... (e.g. NumberSeqModuleAbc)
protected void loadModule()
{
    NumberSeqDatatype datatype = NumberSeqDatatype::construct();

    datatype.parmDatatypeId(extendedTypeNum(AbcOrderId));
    datatype.parmReferenceHelp("Unique key for the Abc order.");
    datatype.parmWizardIsContinuous(false);   // non-continuous
    datatype.parmWizardIsManual(NoYes::No);
    datatype.parmWizardIsChangeDownAllowed(NoYes::No);
    datatype.parmWizardIsChangeUpAllowed(NoYes::No);
    datatype.parmSortField(1);

    datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);

    this.create(datatype);
}

Consuming the number sequence in code

public AbcOrderId getNextOrderId()
{
    NumberSeq   numberSeq;
    AbcOrderId  orderId;

    // Resolve the number sequence configured on the parameters table
    numberSeq = NumberSeq::newGetNum(AbcParameters::numRefAbcOrderId());
    orderId   = numberSeq.num();

    return orderId;
}

Number sequence reference on the parameters table

// Static helper on the parameters table returning the reference
public static NumberSequenceReference numRefAbcOrderId()
{
    return NumberSeqReference::findReference(
        extendedTypeNum(AbcOrderId));
}

Cleaning up an unused continuous number

NumberSeq numberSeq = NumberSeq::newGetNum(AbcParameters::numRefAbcOrderId());
AbcOrderId orderId  = numberSeq.num();

// If the record is NOT saved, return the number (continuous sequences)
if (!recordSaved)
{
    numberSeq.abort();   // releases the number back to the sequence
}

Continuous vs. Non-continuous

Aspect Continuous Non-continuous
Gaps Not allowed Allowed
Performance Slower (locks to preserve order) Faster (pre-allocated blocks)
Recovery on abort Number returned via abort() / cleanup Number simply lost (gap)
Typical use Legal / audit numbering (invoices) Internal IDs where gaps are fine

Points the interviewer wants to hear

  • Number sequences generate unique, formatted IDs for records.
  • Setup = EDT + reference in loadModule() + configured code + parameters form.
  • Consume with NumberSeq::newGetNum(...) then .num().
  • Continuous = no gaps but slower; non-continuous = faster with gaps.
  • Use abort() to return an unused number in a continuous sequence.

Likely Follow-up Questions

  • When would you choose a continuous sequence despite the performance cost?
  • What does numberSeq.abort() do and when is it needed?
  • What is the role of the scope / segment (e.g. DataArea) in a number sequence?
  • How do you make a number sequence manual so users can type their own value?

Key Takeaway

Number sequences provide unique, formatted identifiers tied to an EDT and configured through a reference. Choose continuous when gaps are unacceptable (audit/legal) and non-continuous for performance, and always consume them through the NumberSeq class.