Create, manage, and extend table maps

Completed

Table maps define the fields and methods that operate on one or more record types.

Using table maps that are defined in Application Explorer under Data Model and Maps is a way to capture commonalities between record types more safely. Additionally, using table maps can help prevent incompatible record assignments and simplify business logic for similar tables.

You can create a mapping between tables in the Mapping node or by using the mapping node on the table together with an interface class. You can create some mapping on the map, some on the table, and some on an interface class because you can’t create extensions for table maps.

For example, if you right-click a map or activate the context menu, the Create Extension option is available; however, if you select it, nothing happens. You can create, manage, and extend table maps by using Visual Studio.

Create a map

To add maps to a project, go to the Solution Explorer window, right-click the project or activate the context menu, and then select Add, New item. Then, you can modify these views through the designer and Properties windows. The Table map designer window has a top-level node with a table map name.

The following table lists the top-level property for maps (other nodes work as they would on tables).

Property Description
Name Name of the map

The following table lists the nodes that are available for a table map in the designer.

Node Description
Fields To create fields manually, right-click the Fields node or activate the context menu. Then, select New, Field. You can set the Extended data type on the field.
Field groups Field groups work similar as they do with tables.
Mappings Use to create mapping to tables and to point to map fields in the table. Typically, you perform mappings on a table to do extensions and use interface classes for table-specific logic.
Methods Like methods for tables; however, instead of having the same method on similar tables, you can create them on a table map.
Events The node exists but isn’t used.

Manage table maps

You need to build table maps before you can use them.

Extend table maps

While you can extend tables and classes, you can’t extend table maps. To find the Create extension menu item, right-click the item or activate the context menu. No action occurs if you select Create extension. You must set up mappings in the table-to-table maps, and you can extend those tables. Additionally, if you require special logic, you need to use an interface class.

To set up mappings in a table, locate the table in Application Explorer and then open it in the designer. In the Mappings node, as the following image shows, right-click the table or activate the context menu, and then select New Mapping. Then, enter the map name and field mapping that you want to use.

 Screenshot of the Mappings node.

If you need special logic, create an abstract class for the interface. First, you need to create an abstract class for mapping by using the table-map name prefixed with Interface, as shown in the following code sample:

public abstract class MyCustVendMapInterface
{
   protected   MyCustVendMap           myCustVendMap;
   private     MyCustVendMapInterface  origInstance;
 
   protected void new()
   {
   }
 
   private void initializeMyCustVendMap(MyCustVendMap _myCustVendMap = myCustVendMap)
   {
       myCustVendMap = _myCustVendMap;
   }
 
   public final MyCustVendMap getMyCustVendMap()
   {
       return myCustVendMap;
   }
 
   /// <summary>
   /// Creates a <c>MyCustVendMapInterface</c> object based on the provided <c>MyCustVendMap</c> record.
   /// </summary>
   /// <param name = "_myCustVendMap">A <c>MyCustVendMap</c> record from which to create a <c>MyCustVendMapInterface</c> instance.</param>
   /// <returns>The instantiated <c>MyCustVendMapInterface</c> object.</returns>
   public static MyCustVendMapInterface createInstance(MyCustVendMap _myCustVendMap)
   {
       SysPluginMetadataCollection metadataCollection = new SysPluginMetadataCollection();
 
       metadataCollection.SetManagedValue(classStr(MyCustVendMapInterface), tableId2Name(_myCustVendMap.tableId));
       MyCustVendMapInterface instance = SysPluginFactory::Instance(identifierStr(Dynamics.AX.Application), classStr(MyCustVendMapInterface), metadataCollection);
 
       if (!instance)
       {
           throw error(strFmt("@SYS19306", funcName()));
       }
 
       instance.initializeMyCustVendMap(_myCustVendMap);
 
       return instance;
   }
 
   /// <summary>
   /// Create a <c>MyCustVendMapInterface</c> object based on the <c>MyCustVendMap</c> orig-record.
   /// </summary>
   /// <returns>
   /// The instantiated <c>MyCustVendMapInterface</c> object.
   /// </returns>
   public final MyCustVendMapInterface origInstance()
   {
       if (!origInstance)
       {
           origInstance = MyCustVendMapInterface::createInstance(this.getMyCustVendMap().orig());
       }
 
       return origInstance;
   }
 
   /// <summary>
   /// Gets module type.
   /// </summary>
   /// <returns>
   /// The <c>ModuleCustVend</c> module type.
   /// </returns>
   /// <exception cref="Exception::Error">
   /// TableId is not associated with any module type.
   /// </exception>
   public ModuleCustVend getModule()
   {
       throw error(strFmt("@SYS19306", funcName()));
   }
 
   /// <summary>
   ///    Initializes the current record by copying all fields from another record.
   /// </summary>
   /// <param name="_bomMap">
   ///    A record that is related to the map of <c>BOMMap</c> type.
   /// </param>
   /// <remarks>
   ///    Both records relate to the map of <c>BOMMap</c> type.The <c>inventDimId</c> value will be copied as
   ///    well.
   /// </remarks>
   [Hookable(false)]
   public final void initFromMyCustVendMap(MyCustVendMap _map)
   {
       myCustVendMap.data(_map);
   }
 
}

For each table that requires specific mapping logic, you need to create a new class that extends the interface class, as the following code sample shows:

using System.ComponentModel.Composition;
 
/// <summary>
/// The <c>MyCustVendMapMyCustTable</c> class contains <c>MyCustTable</c> table specific functionality and mapped fields
/// related to the <c>MyCustVendMapInterface</c> table map.
/// </summary>
[ExportMetadata(classStr(MyCustVendMapInterface), tableStr(MyCustVendMap)), ExportAttribute('Dynamics.AX.Application.MyCustVendMapInterface')]
public class MyCustVendMapMyCustTable extends MyCustVendMapInterface
{
   public ModuleCustVend getModule()
   {
       return ModuleCustVend::Cust;
   }
 
}

Next, you need to initiate the interface class in methods for the map, as the following code sample shows:

public class MyCustVendMap extends common
{
   /// <summary>
   /// Create an interface instance.
   /// </summary>
   /// <returns>
   /// The <c>MyCustVendMapInterface</c>.
   /// </returns>
   public MyCustVendMapInterface myCustVendMapInterface()
   {
       return MyCustVendMapInterface::createInstance(this);
   }
 
   /// <summary>
   /// Gets module type.
   /// </summary>
   /// <returns>
   /// The <c>ModuleCustVend</c> module type.
   /// </returns>
   /// <exception cref="Exception::Error">
   /// TableId is not associated with any module type.
   /// </exception>
   public ModuleCustVend getModule()
   {
       return this.custVendTransOpenInterface().getModule();
   }
 
   /// <summary>
   ///    Initializes the current record by copying all fields from another record.
   /// </summary>
   /// <param name="bomMap">
   ///    A record that is related to the map of <c>BOMMap</c> type.
   /// </param>
   /// <remarks>
   ///    Both records relate to the map of <c>BOMMap</c> type.The <c>inventDimId</c> value will be copied as
   ///    well.
   /// </remarks>
   public void initFromMyCustVendMap(MyCustVendMap   _map)
   {
       this.MyCustVendMap::myCustVendMapInterface().initFromMyCustVendMap(_map);
   }
 
}

When you create your maps by using the outlined methods, you can make extensions, including:

  • Table extensions that enable you to use mapping for a table.
  • Code extensions that enable you to change a map’s logic by right-clicking the class or activating the context menu and then selecting Create code extension (Chain of Command). Additionally, you can create pre-event and post-events for methods and use them in an event handler class.