✏️ Explanatory Question

How to Use Map::pack() and Map::create() with Objects in X++

👁 15 Views
📘 Detailed Answer
🟢 Easy
💡

Answer with Explanation

📌 Introduction

In Dynamics 365 Finance & Operations (D365 F&O), we often work with Map objects to store key-value pairs. But what happens when the values are objects — like custom classes — and you want to persist or transfer the map?

X++ gives us Map.pack() and Map::create() methods to help serialize and deserialize maps, but when your map contains objects as values, there's a catch!


🤔 What's the Issue?

By default, X++ containers (used behind the scenes in pack()) do not support object types like class instances or records.

So when you try this:


Map myMap = new Map(Types::String, Types::Class);

and insert a class object as the value, the pack() method won’t work unless your class implements:

  • A pack() method — to convert object state into a container.
  • An create() method — to restore object state from the container.

🧱 Custom Class Example

Let’s define a custom class that will be used as a map value:


class MyData
{
    int amount;
    str description;
  
    public void new(int _amount, str _desc)
    {
        amount = _amount;
        description = _desc;
    }
  
    public container pack()
    {
        return [amount, description];
    }
  
    public static MyData create(container _c)
    {
        int amount = conPeek(_c, 1);
        str description = conPeek(_c, 2);
  
        return new MyData(amount, description);
    }
  
    public str toString()
    {
        return strFmt("Amount: %1, Desc: %2", amount, description);
    }
}


🧪 Runnable Job to Demonstrate It

Here’s a simple job that:

  1. Creates a map with MyData objects.
  2. Packs the map.
  3. Restores it using Map::create()

internal final class Job_MapCreateFromContainerExample
{
    /// <summary>
    /// Class entry point. The system will call this method when a designated menu 
    /// is selected or when execution starts and this class is set as the startup class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        Map mapOriginal = new Map(Types::String, Types::Class);
        Map mapRestored;
        container packedMap;
        str key = "Item1";
        MyData data1 = new MyData(100, "Test object");
  
        // Insert object into map
        mapOriginal.insert(key, data1);
  
        // Pack the map into a container
        packedMap = mapOriginal.pack();
  
        // Recreate the map from packed container
        mapRestored = Map::create(packedMap);
  
        // Lookup the object from restored map
        MyData restoredData = mapRestored.lookup(key);
  
        // Print both
        info("Original: " + data1.toString());
        info("Restored: " + restoredData.toString());
    }
  
}



🧠 Key Learnings

  • Use pack() and create() in your custom classes to serialize/deserialize.
  • This is crucial when your map holds complex types (not just int, str, etc.).
  • Without it, your map won’t restore properly after packing.

✅ When to Use This?

  • When storing map data in TempDB.
  • While caching serialized data.
  • During inter-class or inter-layer data transfer in D365 F&O.

📝 Final Words

Using Map.pack() and Map::create() with objects in X++ isn't difficult once you understand how packing works. Just make sure every object in the map (whether key or value) knows how to serialize and deserialize itself using pack() and create() methods.

Happy coding in Dynamics 365 F&O! 🚀