Skip to main content

DACs, Graphs and Their Extensions Application to Multi-Tenant Instances

  • February 25, 2025
  • 0 replies
  • 24 views

snikomarov36
Acumatica Employee
Forum|alt.badge.img

This post describes how DACs, Graphs and DAC/Graph extensions are applied to Acumatica sites with multiple tenants. The article attempts to answer when and why the code behavior depends on the tenant. Different factors are considered:

  • Location of the code - is it Acumatica source code or customization.
  • Presence of the IsActive method in DAC/Graph extension.
  • Features.xml file.
  • Custom checks for the feature switch in the business logic.

It is easy to reason about instances with a single active tenant. There is no need to worry how the data is shared between active tenants, which entities will be available to which tenants. The things become more complex for multi tenant instances, especially, when the customizations are involved. This is why this article will focus on multi tenant instances and try to answer the following questions: 

  • Are DACs and Graphs are always available to all tenants? Do they depend on the tenant of the current user?
  • What about DAC and Graph extensions? Are their changes applied to every tenant?
  • Are there differences between DAC/Graph extensions declared in customization and DAC/Graph extensions declared in Acumatica source code?

I would like to start with a brief refresh of what tenants are in Acumatica.

Tenants Overview

In Acumatica ERP, a single instance of the application can serve multiple tenants, which represent separate companies. When you create an application instance, you create at least one tenant. Multiple tenants can use the same application instance, with each having completely isolated data. The application looks identical to all tenants, but each tenant has exclusive access to only its data. 

During the installation the installer usually creates the System tenant (which has a Tenant ID of 1) automatically. The System tenant contains the predefined system data, such as roles, numbering sequences, and the wiki-based documentation. The system data is used by all tenants of the same application instance. By default, the System tenant is hidden on all end-user forms. All other user-created tenants inherit the initial configuration and system data from the System tenant. That is, all the data available in the System tenant is visible to other tenants in the same database. During an application update or upgrade, all the data available in the System tenant is replaced, while the data created by users in user-created tenants remains unchanged.

In addition to the System tenant Acumatica Framework supports a hierarchy of tenants that may work with a combination of shared and individual data. Regular tenants may have custom parent tenants configured for sharing of preconfigured system data. You can learn more about tenants on Acumatica Help Portal in this article.
 
Usually, we refer to Acumatica instance as a single tenant instance, if it has only one non-System active tenant. The instance is called multi-tenant instance, if it has more than one non-System active tenant.
 
From the technical side, tenants are implemented as an additional DB column CompanyID which is part of primary keys of almost all DB tables in Acumatica. To enforce data isolation Acumatica Framework automatically adds filtering by the tenant ID of the current user to DB queries. The DB tables that require support of data sharing between tenants use an additional CompanyMask DB column which is a 32-bit mask. You can read more about the multi-tenancy support here.
 

Multi-Tenancy and Customizations

You can publish any customization for a single tenant or for all site's tenants. Customization projects published on multi-tenant instances have some non-obvious aspects. The content of customizations can be split into two categories:

  • Customization parts applied to only a single tenant. These parts are added only to the database. Since the DB data is stored per tenant, such parts can be added to only a single tenant. Some examples of such parts are reports, GIs, dashboards, site map nodes and workflow.
  • Customization parts applied to all tenants unconditionally. These parts change website files and can be published only to multiple tenants. Changes to form layout, custom tables, custom code, and files introduced by the customization project are added to the website files and therefore are available to other tenants.

For all tenants that use the same website, on the Sign-In page and in the About Acumatica box (which opens when you click Tools > About on the form title bar), you can see that the website is customized, but you will not see any published project on the Customization Projects (SM204505) form. This form displays the customization projects that have been uploaded to the current tenant; therefore, no projects are displayed if they have been uploaded and published under another tenant. 

If you publish a customization project to a tenant, the system unpublishes all the previously published customization projects in all the tenants of the website. The best practice is to use only one tenant for uploading packages and publishing customization projects. The website changes will be available to all tenants anyway, and if you need to share database data, you can publish the customization projects to multiple tenants at once. 

 

Let's take a look at a simple example to illustrate the described behavior. Suppose, that you have Acumatica instance with two active tenants, A and B. And you have a customization with a simple DAC extension that just changes the display name of a DAC field for an existing DAC, such as ARInvoice. Now the admin user publishes the customization for tenant A and can see both that the customization is published and that the changes are applied. The user can open the screen AR301000 to see them. If now admin logins to the tenant B, the changes are still applied and visible. However, the list of published customizations on tenant B is empty, there are no uploaded customizations for the tenant B. 

You can find more details about publishing customizations on sites with multiple tenants on our Help Portal in this article.

 

Multi-Tenancy and Set of Active Features

The set of active site's features is stored in the database in the FeatureSet table. This set is tenant-dependent and can be different for different tenants on the same site. This means that all business logic that depends on the activity of some feature is also tenant-dependent and may behave differently for different tenants.
 
There are several places where the business logic behaves differently depending on whether the feature is enabled or not. They are described in the next sections.
 

IsActive method

IsActive method in DAC and Graph extensions controls if the extension is loaded and applied to the DAC or Graph based on the result returned by it. In most cases this method just checks whether some particular feature is enabled like this:
public class MyGraphExt: PXGraphExtension<MyGraph>
{
    public static bool IsActive() => PXAccess.FeatureInstalled<FeaturesSet.someFeature>();
} 

When the IsActive method determines that the extension is not active, the extension won't be loaded and applied. For DAC extensions this means:

  • Fields defined in the DAC extension that should be visible on forms will be automatically hidden. These fields also won't be displayed in DAC Browser
  • If a field is used in a generic inquiry as a column in the results grid or in a report as a text box, the field is also hidden. If the field is used in a configuration of a generic inquiry or a report, an error is thrown indicating that the field is not found.
  • Database fields defined in the DAC extension will not be in SQL queries generated by the system. So if you have a BQL query that explicitly adds OrderBy, GroupBy, Where, and possibly other statements to such a field, an error is thrown indicating that the field is not found.
  • In a graph or a graph extension, if an event handler is declared for a field of a disabled DAC extension, the event handler is not executed.

For Graph extensions this means:

  • Form controls bound to views defined in that graph extension are automatically hidden.
  • Event handlers implemented in the graph extension are ignored. Overridden event handlers and methods with the PXOverride attribute are also ignored.
  • Views defined in the graph extension will not be available.

You can read more details about the IsActive method and conditional activation of extensions here:

Features.xml File

Features.xml file is another mechanism to bind selected Acumatica functionality to the activation of a particular feature. It is an XML file which is embedded into the PX.Data assembly as an assembly resource. At runtime the configuration in this file is used to determine the availability of some screens, and visibility of DAC fields and Graph actions depending on whether the feature specified for them in the file is enabled or not. Most of main Acumatica modules activated by the feature switch are specified in this file.  
 
You can read details about the Features.xml file in this Help Portal article. Note, that Features.xml file has some differences with the IsActive method:
  • The DAC fields with access controlled by Features.xml file will be hidden in the UI but still loaded into the corresponding PXCache unlike DAC fields from a DAC extensions disabled via the IsActive method. These fields also will be displayed in DAC browser.
  • The Features.xml file can control access to DAC fields declared in DACs while the IsActive method can control availability only for fields declared in DAC extensions.

External Acumatica developers, such as ISVs and OEMs, can also develop their own features and a custom Features.xml file. This is documented on Help Portal here. However, this is an older, less convenient approach comparing to the IsActive method. Thus, it is not frequently used.

 

Custom Feature Checks

The last approach is the capability to directly check in your code whether some feature is active, for example, in the if statement. You can do it like this:

public class MyGraph : PXGraph<MyGraph >
{
    private void Foo()
    {
        if (PXAccess.FeatureInstalled<FeaturesSet.someFeature>())
        {
            //Logic when feature is enabled
        }
        else
        {
            //Logic when feature is disabled
        }
    }
} 

 

This approach can be used both in the source code and customizations, it allows to change system's behavior in arbitrary places based on whether a particular feature is enabled or not.

This approach currently it is not recommended and heavily discouraged by Acumatica!

 

Despite being very flexible this approach has several serious flaws:

  • This approach usually requires to write a lot of boilerplate checks in different places to completely separate behavior between cases when feature is enabled and when it is disabled.
  • The big amount of boilerplate checks leads to complex, hard to maintain business logic which is error-prone. It becomes simple to introduce a bug by forgetting to write a check for the feature in some place.
  • The big amount of feature checks introduce a performance overhead because these checks are constantly evaluated. This approach also consumes more resources comparing to the approach with the IsActive method there due to:
    • Redundant DAC fields loaded into PXCache from DAC extensions despite the corresponding feature being disabled
    • Redundant Graph event handlers from Graph extensions constantly firing despite the corresponding feature being disabled

The approach with the IsActive method was created to address these problems. This is why currently the best practice is to design your logic around DAC and Graph extensions. Still, the approach with custom checks is the oldest one and it is possible to see it in the legacy Acumatica code.

 

DACs, Graphs and Extensions in Multi-Tenant Instance

Now, after describing different things that may change the behavior of the code depending on the current tenant, let's summarize how this applies to DACs, Graphs and their extensions in a multi-tenant instance. Will they be equally available to every tenant present on the instance, for example, in GI Designer? As the article mentions, it depends on several factors:

  • Where the code is located.
    • If DAC, Graph or DAC/Graph extension is declared in the Acumatica source code, then it is available for every tenant assuming that all other factors do not affect it.
    • If DAC, Graph or DAC/Graph extension is declared in the customization, then it depends on whether the customization was published for at least one tenant:
      • If yes, then DAC, Graph or DAC/Graph extension will be available for every tenant assuming that all other factors do not affect it.
      • If no, then DAC, Graph or DAC/Graph extension is not available for all tenant.
  • For DAC and Graph extensions their availability depends on whether they declare the IsActive method which depends on whether some feature is enabled or not on the site. If there is such method, then the extension depends on the current tenant and will be applied only for tenants that have this feature enabled.
  • Access to DACs, Graphs and DAC/Graph extensions may be configured in the Features.xml file. If this is the case, then the behavior of these code entities depend on the set of the currently active features which depends on the current tenant.
  • The business logic in Graphs and Graphs extensions (and other places too) may contain custom checks whether some feature is active or not. The code may change its behavior depending on the result of such checks which makes it dependent on the current tenant.

Here is the diagram to illustrate this for DACs and Graphs:

DAC or Graph Application to a Multi-Tenant Instance

And here is the diagram to illustrate this for DAC and Graph extensions

DAC Extension or Graph Extension Application to a Multi-Tenant Instance

That’s all about application of DACs, Graphs and their extensions on multi-tenant instances.
Thank you for your attention!

Did this topic help you find an answer to your question?

0 replies

Be the first to reply!

Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings