How to use the setIsValid Method in Dataverse / Dynamics 365


We can use the setIsValid method for validating field values in Model-driven apps. This method helps ensure that the data entered by users meets the required criteria before it’s processed or saved.

The setIsValid method is used to set the validity of a column’s value. It can mark a field as valid or invalid based on custom validation logic.

formContext.getAttribute(arg).setIsValid(bool, message);

bool: A Boolean value. Set to false to mark the column value as invalid, and true to mark it as valid.

message: (Optional) A string containing the message to display when the value is invalid.

Below we are using the setIsValid method in the function that ensures that the “End Date” is earlier than or equal to the “Start Date”, else it will mark the “End Date” as invalid.

function validateDates(executionContext) {
    var formContext = executionContext.getFormContext();
    var startDate = formContext.getAttribute("custom_startdate");
    var endDate = formContext.getAttribute("custom_enddate");
  
    if (startDate && endDate && endDate.getValue() <= startDate.getValue()) {
        endDate.setIsValid(false, "End Date must be after Start Date.");
    } else {
        endDate.setIsValid(true);
    }
}

We have it registered in the On Change of the ‘Start Date’ and ‘End Date’ fields.

Here if we try saving the record, if the End Date is smaller than the Start Date, we will get the message specified.

Hope it helps..

Advertisements

Manage solution dependencies easily through the refreshed look – Dataverse


In Dataverse, solution dependencies are a vital aspect of managing and deploying applications. Dependencies ensure that required components are present for a solution to work seamlessly across environments. However, with complex solutions, understanding and managing these dependencies can become overwhelming.

The updated dependencies page is designed to simplify dependency management by offering a more intuitive, action-driven experience.

Select a particular component in the solution, right-click>> Advanced >> Show dependencies.

We can see 3 different tabs.

Delete Blocked By (tab): Displays any dependencies preventing deletion of a component. Below we can see that for the Age column, it shows Contact’s System Form as the dependency.

A screenshot of a computer

Description automatically generated

Clicking on the Open option takes us to the component page, where we can see all the forms for the contact table.

A screenshot of a computer

Description automatically generated

Used By (tab): Lists other components dependent on the selected component.

Uses (tab): Shows dependencies that the selected component relies upon.

A screenshot of a computer

Description automatically generated

On clicking Open, it opens the Columns page for that table.

A screenshot of a computer

Description automatically generated

The different actions that we can take are Open and inspect the object, Delete the object, Remove dependency, and open the relevant documentation.

Below we have selected the option Remove dependency. As we saw the dependency here refers to the Contact System form in which we have the age field used.

A screenshot of a computer

Description automatically generated
A screenshot of a computer

Description automatically generated

Select Remove.

A screenshot of a computer

Description automatically generated

We get the success message after the successful removal of the dependency.

i.e. we can see the field removed from the blocking Contact’s System form.

Now if we want we can easily delete that particular field with no object blocking the delete.

Lastly, the Delete option for the solution allows the delete (uninstall) the solution that has dependencies on the solution component.

Get all the details here.

Hope it helps..

Advertisements

Disable recent records (Disable most recently used items) for the Lookup field used in the Business Process Flow (Dataverse / Dynamics 365)


Suppose we have the below Customer Lookup in the Sample Stage of a Business Process Flow.

As we can see the lookup shows the Recent records there.

A screenshot of a computer

Description automatically generated

Now say we have applied filtering to the lookup using addPreSearch so we need to disable the recent records options in it.

To do so for the fields in BPF –

Open the corresponding table of the BPF (will have the same name as BPF)

A hand pointing to a computer screen

Description automatically generated

Open the form, select the Customer (lookup) field from the Tree View, and check the Disable most recently used items (save and publish the change)

A screenshot of a computer

Description automatically generated

As expected we can now see the recent records options not appearing for the Customer lookup in the BPF.

A screenshot of a computer

Description automatically generated

Hope it helps..

Advertisements

How to – Delete the elastic table records (Dataverse)


Recently we wrote an SSIS package to delete the Elastic Table records using KingswaySoft’s Integration Toolkit for Dynamics 365.

A screenshot of a computer

Description automatically generated

We had mapped the primary field for deletion and the package was also showing success.

A screenshot of a computer

Description automatically generated

However back in our CRM / Sales Hub app, we saw that none of the records were deleted (total – 48999)

A screenshot of a computer

Description automatically generated

The reason it was showing success is that we had specified the Ignore Error option in our CDS Destination component.

A screenshot of a computer

Description automatically generated

Then we created 2 more records but didn’t specify the partition ID for them.

A screenshot of a computer

Description automatically generated

This time on the successful run of the package we can see those 2 new records getting deleted for which we didn’t specify any partition ID i.e. Test 1 and Test 2 records were deleted successfully.

A screenshot of a computer

Description automatically generated

If we check the Microsoft docs it mentions that we need to include the partition ID using the alternate key to delete those records using the DeleteMultiple request.

Could not find a way to specify an Alternate Key in the CDS Destination component for the Delete message and if we try deleting the records one by one instead of using the DeleteMultiple request we get the below error.

A screenshot of a computer

Description automatically generated
A screenshot of a computer

Description automatically generated

[CDS Destination [2]] Error: An error occurred with the following error message: “System.Exception: Error(s) occurred when processing the batch: [1] KingswaySoft.IntegrationToolkit.DynamicsCrm.WebAPI.WebApiServiceException: The remote server returned an error: (404) Not Found. (Error Type / Reason: NotFound, Detailed Message: {“error”:{“code”:”0x80040217″,”message”:”The HTTP status code of the response was not expected (404).\n\nStatus: 404\nResponse: \n{\”error\”:{\”message\”:\”Could not find item ‘b3a70971-9674-ef11-a671-6045bdfe58ee’.\”,\”details\”:[{\”message\”:\”\\r\\nErrors : [\\r\\n \\\”Resource Not Found. Learn more: https://aka.ms/cosmosdb-tsg-not-found\\\”\\r\\n]\\r\\n\”}]}}”}}) (SSIS Integration Toolkit for Microsoft Dynamics 365, v23.2.2.32701 – DtsDebugHost, v16.0.5270.0)System.Net.WebException

As expected, using CrmServiceClient also if we do not include partitionid we will get the below error for the records that have partition id specified.

The HTTP status code of the response was not expected (404).

Response:

{“error”:{“message”:”Could not find item ‘b3a70971-9674-ef11-a671-6045bdfe58ee’.”,”details”:[{“message”:”\r\nErrors : [\r\n \”Resource Not Found. Learn more: https://aka.ms/cosmosdb-tsg-not-found\”\r\n]\r\n”}]}}

Here we can specify the partitionId parameter to delete those records having the partitionId specified in the DeleteRequest

For DeleteMultiple Request we need to provide the alternate key as shown below.

A screen shot of a computer code

Description automatically generated

We will have the alternate key auto-created by the system when we create an elastic table.

Sample Code –

 var myServiceClient = new CrmServiceClient(connectionString);
        var query = new QueryExpression("custom_myelastictable");
        query.ColumnSet.AddColumns("custom_name", "partitionid");
        var myElasticTableCollection = myServiceClient.RetrieveMultiple(query);
        var lstEntityRefCollection = new EntityReferenceCollection();

        // Delete Request
        foreach (var elasticTable in myElasticTableCollection.Entities)
        {
            var deleteRequest = new DeleteRequest();
            deleteRequest.Target = new EntityReference("custom_myelastictable", elasticTable.Id);
            deleteRequest.Parameters["partitionId"] = elasticTable.Attributes["partitionid"];
            var response = myServiceClient.Execute(deleteRequest);
        }

        // DeleteMultiple Request 
       
        foreach (var elasticTable in myElasticTableCollection.Entities)
        {
            var entityRef = new EntityReference("custom_myelastictable", elasticTable.Id);
            entityRef.KeyAttributes.Add("custom_myelastictableid", elasticTable.Id);
            entityRef.KeyAttributes.Add("partitionid", elasticTable.Attributes["partitionid"]);
            lstEntityRefCollection.Add(entityRef);
        }

        var deleteMultipleRequest = new OrganizationRequest();
        deleteMultipleRequest.RequestName = "DeleteMultiple";
        deleteMultipleRequest.Parameters.Add("Targets", lstEntityRefCollection);
        myServiceClient.Execute(deleteMultipleRequest);

Hope it helps..

Advertisements

JavaScript for fields in Business Process Flow (few key points)– Dataverse / Dynamics 365


Suppose we have the following fields in the form as well as in the business process flow stage for the lead.

  • Rating and Email in the form.
  • Rating 1, Rating 2, and Email in the BPF.
A screenshot of a computer

Description automatically generated

And let us apply the below JavaScript on the form load.

A screenshot of a computer code
Description automatically generated

On opening the lead form below is the result we get.

formContext. getControl(“leadqualitycode”).setVisible(true);

Sets the Rating field visible on the form.

formContext. getControl(“header_process_leadqualitycode”).setVisible(false);

Hides the Rating 1 field on the BPF.

formContext.getControl(“header_process_leadqualitycode_1”).setVisible(true);

Set the Rating 2 field visible on the BPF.

As the getControl method is used to show or hide the field it only applies to the field being referenced. That is why we only have the Rating 1 field on the BPF being hidden.

formContext. getAttribute(“leadqualitycode”).setRequiredLevel(“required”);

Set the Rating field on the form as mandatory.

formContext.getControl(“header_process_leadqualitycode_1”). getAttribute().setRequiredLevel(“none”);

Set the Rating 2 field in BPF as non-mandatory

We are setting the Rating field on the form as mandatory, in the next line we are setting the Rating 2 field on the BPF as non-mandatory, the final result is Rating field is non-mandatory on the form as well because here getAttribute method is used which applies to the attribute level so gets applied to all its corresponding controls.

formContext.getAttribute(“leadqualitycode”).setValue(3)

Set the Rating field on the form’s value to Cold

As getAttribute is being used the value set for the Rating field on the form applies to the field in the BPF also.

formContext. getControl(“header_process_leadqualitycode_1”).setDisabled(true);

Set the Rating 2 BPF field as disabled.

As getControl is used it only applies/disables the Rating 2 field on the BPF.

formContext.getControl(“header_process_emailaddress1”). getAttribute().setValue(“test@test.hotmail.com”);

Set the value of the Email address field on the form.

As getAttribute is being used the value set for the Email field on the BPF also applies to the field on the form.

formContext.getControl(“header_process_leadqualitycode_1”). getAttribute().addOnChange(function () { var lastNameValue = formContext.getAttribute(“lastname”).getValue(); if (lastNameValue) { alert(“Hello, ” + lastNameValue + “!”); } else { alert(“Hello World!”); } });

Adds the on-change event to the Rating 2 field on the BPF.

As getAttribute is being used the on-change event handler is applied to both the fields on the form as well as field.

Check other posts on BPF –

https://nishantrana.me/2024/10/09/use-javascript-to-enable-a-field-only-if-the-stage-is-active-in-business-process-flow-dynamics-365-dataverse/

https://nishantrana.me/2024/10/10/use-javascript-to-add-onchange-event-to-a-field-in-the-business-process-flow/

Hope it helps..

Advertisements

Fixed – EntityState must be set to null, Created (for Create message) or Changed (for Update message) exception in Dataverse / Dynamics 365


We might get this error while trying to update one of the records.

Exception Message: EntityState must be set to null, Created (for Create message) or Changed (for Update message).

EntityState of primaryEntity: Unchanged, RequestName: Update

ErrorCode: -2147220989

A computer screen shot of a computer

Description automatically generated

The error occurs when OrganizationServiceContext tries to update an entity that has not been marked as modified. The EntityState remains Unchanged, and Dataverse expects it to be Changed or null for update operations.

OrganizationServiceContext automatically tracks entities’ states. When we retrieve an entity, it is set to Unchanged by default.

If we modify the entity without informing the context (e.g., using UpdateObject()), the context still thinks the entity is Unchanged, leading to this error during the update process.

A screenshot of a computer

Description automatically generated

This error typically happens within OrganizationServiceContext since it relies on internal state-tracking mechanisms, with IOrganizationService (e.g., Retrieve or RetrieveMultiple), we typically don’t run into this error because entities retrieved via IOrganizationService aren’t tracked in the same way.

There are 2 ways to resolve this error.

  1. Use UpdateObject, it explicitly tells the context that the entity has been changed followed by SaveChanges() to commit the changes.
A computer screen shot of a program

Description automatically generated

2. Create a new Entity object for update.

Sample Code –

 if (myServiceClient.IsReady)
        {
            using (var context = new OrganizationServiceContext(myServiceClient))
            {
                // Retrieve leads where the 'lastname' contains 'Test'
                var leadColl = from lead in context.CreateQuery("lead")
                               where lead.GetAttributeValue<string>("lastname").Contains("Test")
                               select lead;

                // use Update Object
                foreach (var lead in leadColl)
                {
                    lead.Attributes["subject"] = "Updated Subject" + DateTime.Now.ToLongTimeString();
                    context.UpdateObject(lead);
                    context.SaveChanges();
                }

                // or create a new Entity object
                foreach (var lead in leadColl)
                {
                    Entity leadToUpdate = new Entity("lead", lead.Id)
                    {
                        ["subject"] = "Updated Subject" + DateTime.Now.ToLongTimeString()
                    };
                    myServiceClient.Update(leadToUpdate);
                }     
            }
        }

Hope it helps..

Advertisements