Programmatically Managing Table Visibility in Model-Driven Apps

By | August 3, 2023

Introduction

During our project, we encountered an issue related to dynamically adding or removing table relationships in an existing multi-table setup in the manage solution. Specifically, we implemented a custom multi-table lookup field called “Client” on the “Retailer” entity. However, when we tried to create a 1: N relationship between the “Retailer” entity and another custom entity called “Registration,” the “Registration” entity did not appear in the options for the “Client” multi-table lookup. Instead, it only showed the “Contact” entity.

Model-Driven Apps

Upon investigation, we realized that the reason for the “Registration” entity’s absence in the “Client” lookup was that the “Registration” entity was not present in the app designer. As a result, it wasn’t visible in the lookup field’s options.

Model Driven App

In the below screenshot Registration entity is not present in the app designer.

Model-Driven Apps

To make the “Registration” entity available in the “Client” lookup, we need to ensure that it is added to the app designer first. This way, it will be included as an option when establishing the relationship between the “Retailer” entity and the “Registration” entity in the future.

After investigation, we discovered an API that enables the addition of the Table to the app designer views.

The code for the same is as follows:

private void AddRemoveEntity(PluginConfig config)

{

Entity targetEntity = new Entity();

 

// Retrieve the existing entity metadata

RetrieveEntityRequest retrieveEntityRequest = new RetrieveEntityRequest

{

LogicalName = cr41e_registration,

EntityFilters = EntityFilters.Entity,

};

RetrieveEntityResponse retrieveEntityResponse = (RetrieveEntityResponse)config.Service.Execute(retrieveEntityRequest);

EntityMetadata entityMetadata = retrieveEntityResponse.EntityMetadata;

 

QueryExpression query = new QueryExpression("appmodule");

query.ColumnSet = new ColumnSet("appmoduleid");

query.Criteria.AddCondition("uniquename", ConditionOperator.Equal, "cr41e_DemoApp");

 

EntityCollection appEntities = config.Service.RetrieveMultiple(query);

 

if (appEntities.Entities.Count != 1)

{

Console.WriteLine("App with a unique name not found or multiple apps found with the same name.");

return;

}

 

Guid appId = appEntities.Entities[0].Id;

 

Guid[] componentIds = new Guid[]

{

// Add your component IDs here.

entityMetadata.MetadataId.Value,

// Add more component IDs as needed.

};

EntityReferenceCollection components = new EntityReferenceCollection();

 

// Add each component to the collection.

foreach (Guid componentId in componentIds)

{

EntityReference componentRef = new EntityReference(entityLogicalName, componentId);

components.Add(componentRef);

}

 

// Add the entity to the app

AddAppComponentsRequest addAppComponentRequest = new AddAppComponentsRequest

{

Components = components,

AppId = appId, // Replace with your app's solution unique name

};

 

config.Service.Execute(removeAppComponentRequest);

PublishAll(errorLog, config, ref  traceLogBuilder);

 

}

 

}

In the screenshot provided, we have successfully added the “Registration” entity to the app designer views. Now, the “Registration” entity is visible and accessible within the application’s design, allowing us to utilize its functionalities and data in various aspects of the application.

Model-Driven Apps

After adding the “Registration” entity to the app designer, we can now see the “Registration” entity appearing in the options of the “Client” multi-lookup, as depicted in the image below.

Model-Driven Apps

It’s essential to note that sometimes, even after adding a table in the app designer, it may not be immediately available for search in certain multilookup. To ensure that the newly added table is accessible in the desired multilookup, we need to perform a publish operation. As a result, we have implemented code to handle the publish action, ensuring that any changes made to the app’s components, including the addition of the “Registration” entity, take effect and become visible as expected.

The code for publish operation is as below:

public void PublishAll()

{

PublishAllXmlRequest publishXmlRequest = null;

string functionName = "PublishAll";

 

publishXmlRequest = new PublishAllXmlRequest();

 

config.Service.Execute(publishXmlRequest);

Utility.SetTrace($" publish all done", config, ref traceLogBuilder);

 

}

In our specific scenario, when we delete the 1:N relationship between “Client” and “Registration,” it is necessary to remove the “Registration” entity from the app designer views as well. To achieve this, we have implemented the following API to handle the removal of the entity from the app designer:

RemoveAppComponentsRequest removeAppComponentRequest = new RemoveAppComponentsRequest

{

Components = components,

AppId = appId, // Replace with your app's solution unique name

};

config.Service.Execute(removeAppComponentRequest);

PublishAll(errorLog, config, ref  traceLogBuilder);

Conclusion

By utilizing the provided code, we can seamlessly add or remove entities in the app designer