Sunday 8 September 2019

Virtual Entity : Chapter 3 – Translating an advanced find query to a query understood by the Data Source

Overview

This is of the four-part series tutorial where I am trying to explain virtual entity in Dynamics 365 CE. The chapters are,
  • Chapter 1 - Core concept and definition
  • Chapter 2 - Setting up custom data source and custom provider and hands on code
  • Chapter 3 – Introducing searching capability (Current)
  • Chapter 4 – Storing the settings for the api.

The demo is created on a 30 day trial edition of Dynamics 365. All the code mentioned in the tutorial is available on my Github Repo. All the customization used in the tutorial is found on releases section of the same Github repo. I have tagged the binaries as pre-release as I have not used the code in any production scenario. Although I am keeping an eye out for any possible bug reported in Github or to my email but please consider all the code as is. In the code I have integrated country Api found in this page along with the description of the each end point. A huge shout out to ApiLayer. A big thanks to Mark Findlater for reviewing the blog.

Chapter - 3

So now we have set up our Virtual Entity and it is connected to a Custom Data Provider. The Data Provider is getting data from third-party Data Source in an advanced find view. We can also open the record and see the details in a form.

Here are some problems that we have not yet discussed 
  • Can we run a query on the advanced find view so that only selected records are returned?
  • What happens if we have different Dynamics instance (like dev-test-uat-production) and we have custom API environment for each? Do we need to register a Custom Provider like I did in Part 1 and Part 2 all over again for each environment?


This chapter will answer the first of the above questions. Ready?

Visitor Pattern and Query Expression Visitor

I am not going to go into huge detail about the visitor pattern. I found that this article explains the whole pattern very clearly. Let me, however, give you some idea of the problem we are trying to solve here, in our case we are exposing external data from and API. You might want to expose data directly from an SQL server or may be from even an azure logic app. So your users in CRM need be able to construct a query in Dynamics in fetch xml in advanced find. When the user clicks on search this comes to your retrieve multiple plugin. It becomes the responsibility of your plug in to translate the fetch xml (or query expression) to something that your data source can understand. This is where visitor pattern comes it. Newly introduced Query Expression Visitor class in the CRM SDK leverages this pattern to translate fetch queries to the query that the data source API will understand. The translation code still needs to be written by you. The pattern is there to encapsulate it. A similar example of this can be found in this MS doc I recommend reading and understanding the article in the first link for the explanation of the pattern before proceeding any further with this.

Code Example

So first up I am going introduce two new methods in my CountryGet class that will search countries by capital and search countries by region. They are quite self-explanatory. The former searches all the countries by given capital while the later searches country by region. After adding the code to call the apis my class for calling the API looks like below,


Now comes the visitor class – very straight forward nothing super crafty about it.


My Retrieve Multiple now ties everything up. Notice that I have also introduced tracing.


I have cleaned the code just to be very nit-picking, I introduced factory pattern in the country get like so,


For that my visitor is slightly changed as well.


And my Retrieve Multiple is a breeze


As you could rightly say by now formatting the query for a Custom Provider is not that hard, but it is a bit of work nonetheless. You should consider allowing support only for certain operator like I did on the code above. Like you should consider rejecting any queries that has date operator. The problem also become some order of magnitude harder when the user use combination of filter criteria.
You should also consider allowing search on the field that you support. In this way you can give searchability when it is relevant.



No comments: