Monday, March 31, 2025

D365 Environments and Solutions

 

D365 Environments and Solutions

 Well, I don’t think I could have picked a more ambiguous title.  Let me see if I can clarify what I’m actually going to talk about in this blog.  If we look at Environments first. 

 As always, this is not a definitive guide and it’s not the intention to teach you the intricacies of application development.  It is more aimed at giving you an understanding of what these things are and how we may use them in the D365 (CRM) space.

What is an Environment in the Dynamics 365 Space?

Here’s a simplified definition:

An environment is place where we can create store and manage apps, the security, process flows, the security who can see them etc.   Think if it as a big bucket that contains everything you need to use the apps contained within it.

Why do we need environments in D365?

At the very least we need one. The ‘Production’ environment, which is great for a finished application that is never going to be updated (how many of those exist?). Typically, we have more.  As a developer or a student learning their way around you might want create environments to hold and sperate or different designs or development ideas or projects.  You might be building two completely different D365 apps. and want to keep it all separated so that one change in one app does not affect the other.

In the commercial space we normally have as a minimum a Development Environment and a Production Environment, the larger the organisation or scale of the application the more environments you likely to have.  The table below shows how a large organisation might structure their D365 environments

Environment Name

Description

Dev

The abbreviation for Development. This can be a single development environment whereby all the developers work, or it can be a developers own personal environment where only their changes are created and managed.

System Integration

Once the developers have created their functions or changes, the System Integration is used to ensure that changes do not adversely affect any of the systems or changes that are attached or interfaced to.  This is typically where the IT teams will test the API integrations to other applications or other types of environments (Think accounting system, HR system, ERP systems etc.)

Test (IT)

On the developers have completed their integration testing,  it will often then be passed to the test team for further testing.  Larger organisations will typically have this environment for regression testing and may have automated robot scripts testing the application to ensure that previously working items are not adversely affected by anything from the System Integration.

User Acceptance Testing (UAT)

Once the IT testing is completed, it is handed over to the User Acceptance Team.  Here a selected, cross section of users will test the application from the user’s perspective.  They typically contrate on the user experience and usability of the application (fault testing should have already been completed by this stage).  This environment is can also be a full copy of production that the is updated with the new changes, so that the acceptance team can see the changes in the context of the live environment (production) but without the risk of testing in the actual production environment.  This environment is sometimes called ‘Pre-Production’

Production

The live environment, that all users work in, this contains all the current working updates and is what is used as part of the ongoing ‘Business as usual’ processes.

 

In summary, an environment is a space (think box) that contains all the constituent parts needed to run the application.  We have multiple environments purely to manage the risk of making changes to the D365 application.

If the Environment can be considered as a Box,
What’s the ‘Solution’?

Microsoft define the D365 solution as:

‘a packaged unit of software that extends the platform, allowing customizers and developers to author, package, and maintain extensions, and deploy them across different environments.’

What does that mean really?  In its simplest form, it is a way of combining changes (Configuration of customisation) together in a single file that can be used to add those changes to another environment or application.  Think ‘transportation device’.  A solution can contain, whole apps, Site Maps, Entities (record types), Option sets (think list of countries as an example)  Web Resources (For example these can be Java Scripts, Icons, Images, External Web Links), in fact (pretty much) anything that is contained with the D365 environment can be put into a solution.

Managed or Unmanaged?

If you have already looked under the covers in the D365 environments, you may have already seen that Solutions are Managed or Unmanaged.   We’ll talk about that next.  We’ve already said that a solution is a way of combining changes or updates into a single transportable unit.  If you look at the D365 environment as a whole, you’ll see there are thousands of attributes across hundreds of entities, scripts, actions and process (and more).

 Now let’s suppose you want to make some layout changes on a couple of the forms (User interface) for couple of the entities.   You could open up the default solution (That contains everything for that environment), or you could create a new solution and just pull in the items you want to change.  For example, you might want to add an Address Validation and Lookup function to the address on the Account and Contact forms.  You might create a Solution and call it “Address Validation Changes’ and add the two entities to the solution.

NOTE

You can add the whole entity along with all its consistent parts and meta data or you can just add the bits you actually need to make the updates which is the preferred approach and you’ll see why when we talk about ‘Managed Solutions’

Assuming you have added the Account and Contact entities to your solution along with the relevant address fields your address validation with work with or update you will end up with a solution that contains about a dozen or so items.  That makes it much easier to see, deal with and manage.  As you make your changes in the solution and then publish it, those changes are now live in our environment. Having that small solution, means is fast to save and only loads / updates those few items (much faster than having to read through and update the entire default solution).

We have already spoken about that fact the solution is our transport device more moving changes between environments.  Now we have our solution, we can export it from our current environment and ‘Import’ into another one. With a nice small solution like this example, it should have a minute or two.

When you import a solution into a new environment, it instantly becomes part of that environment and overwrites what’s already there (with the same database name) with your changes.  Just image if you exported the whole default solution, with your changes and then imported it into new environment, and unbeknown to you, someone else had incomplete changes elsewhere in the system, there could be very unwanted ramifications and how long would it take to find them?   Keeping your solution to just the minimum required items helps avoid this.

What if I want to reverse out my updates I hear you ask, can I just ‘Undo’ my Import?

What a great question, I’m glad you asked.  When you import a solution that is unmanaged (its unmanaged unless you export it as a ‘Managed’ solution) it is now part of the default solution, the only way to ‘reverse it’ is to go into the environment and edit the items and change them to what you want them to be.  If you’ve only changed a couple of fields, not that big a deal, you say, but what if its several hundred attributes across 20 or 30 entities and web resources, that could get really messy and very, very time consuming.  Not to mention it’s not a good look in your next team meeting while you explain why you have no capacity for the next few weeks / months…

How do I Manage my solutions?

Don’t panic, the chaps at Microsoft have given you a way to make the process of ‘managing’ your solutions much less painful.  An unmanaged and a Managed solution are exactly the same other than one very subtle difference (that has a knock-on effect).  When you export your solution, there is an option to export it as a ‘Managed Solution’.   

What this does is in simple terms is adds a wrapper around your work.  The ‘Managed’ part of it tells application to create another set of meta data (hidden from you) related to your changes that locks and tracks them in the new environment.   Now when your ‘managed solution’ is imported to another environment, there’s a new feature that allows you remove (delete it) from the environment.

So why don’t we just make everything a ‘Managed solution’?

The easiest way to answer this question is that ‘Unmanaged Solutions’ are really for developers to group there work together in manageable chunks whereas ‘Managed Solutions’ are really intended for the distribution of a ‘complete’ functions or discrete chunks.  For example, a software vendor would sell their D365 updates as discreate pieces of code wrapped in a managed solution, obfuscating their (IP) code and locking the custom components within it. 

There are some other aspects of a managed solution that ‘might’ stop you from wanting to use it

·         You can't add or remove solution components in a managed solution.

  • You can't export a managed solution.
  • Deleting a managed solution uninstalls all the solution components in it.

There is also the concept of ‘Managed Properties’.  With a managed solution you can decide whether or not to allow some components within it to be customised by other solutions. 

This brings us to the concept of ‘Layering’ which is the ability to add multiple managed solutions with over lapping components.   By this I mean, it is possible to create a managed solution then create a second managed solution that add to or changes to the components of the first one. 

As I mention in most of my posts, I’m not trying to teach the intricacies of programming or managing D365 systems but rather give you a taster of what’s available to you.  If you want to know more about Managed and unmanaged solutions and which to use for what and when, Microsoft learning is a great place to start and the following link delves into this in greater detail. : https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/introduction-solutions?view=op-9-1

 

 

Thursday, March 20, 2025

Defensive Programming Pt 2 - Try Catch Throw, Finally.

 Defensive Programming Pt 2 - Try Catch Throw, Finally.

 In this second part, we look at what we can do or how we can deal with errors when they happen.  We’ve already looked at how to check if a field that we want to programmatically interact with is there and if it’s the type we’re expecting.  Now let’s look at the built-in feature referred to as ‘Try-Catch’ that we can use to help us deal with errors in JavaScript.  Before we do, let give some context.  When we write code, there is always a part that does something, maybe it’s a calculation or making a field mandatory.  Let’s suppose we’ve made a mistake in the typing, which will cause a code crash.   We never want the code to crash, it’s just not a good look. 

If we use the example from before, but lets make a change so it fails.  We’ll change setValue(now);  to SETvalue(now);

 

ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
      Var dateFld == formContext.getAttribute("new_lastcontactdate");
         if(null !== dateFld){
            var fldType == dateFld.getAttributeType();
            If (fldType == "datetime"){
               var now = new Date();
               formContext.getAttribute("new_lastcontactdate").SETvalue(now);
            }
            else {
               return;
            }
         }
         else {
           return;
         }
   }
}

In the runtime, this will create an error with a message popping up in the user interface.  The standard messages are designed for programmers and don’t mean much, if anything at all to the end user, if anything it just annoys them and puts them off using it.

 Obviously, mistakes will happen but, we can do our best to minimise any issues and shield the user from the often terse message that gets popped on to the screen.

 

Let’s Try and Catch that error

NOTE:  Let me reiterate, these posts are not meant to be teaching you ‘How’ to write programs, or as any form of definitive guide, they are here to trigger some thought processes and answer some questions at a higher level.

 

JavaScript has this neat feature, shared with other languages too, that allows you to trap an error and decide how you deal with it. It’s referred to as the ‘Try-Catch’ and here in its most basic form is the skeleton code for the JavaScript Try-Catch


try {
  Block of code to try
}
catch(err) {
  Block of code to handle errors
}

The ‘try’ block braces go around your execution code. In our example for the setDate function the code is really simple and there is only one real area that is likely to cause an error.   However, as you build up more code and complexity, you may have multiple execution lines that could cause a potential error.  You don’t need to have 1 try catch around each line, but also, you don’t want to have one try-catch around your entire set of functions.  It’s all about getting the balance right.  I like to keep my try-catch blocks small and distinct, by which I mean I try and group them to match the function, or areas within a function that makes sense (to me at least).   There are lots of software blogs out there that can give you more guidance on when and where to use the try-catch, my advise is start small and get comfortable with using it.

 Here is our setDate function with the try-catch added. 


ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
      Var dateFld == formContext.getAttribute("new_lastcontactdate");
         if(null !== dateFld){
           
            var fldType == dateFld.getAttributeType();
            If (fldType == "datetime"){
               var now = new Date();
               try {
                  formContext.getAttribute("new_lastcontactdate").SETvalue(now);
              }
              Catch(err){// this is where we deal with any errors from the above try
                 alert(“There has been an error setting the date: ” + err);
              }
            }
            else {
               return;
            }
         }
         else {
           return;
         }
   }
}
 

In our example above the 'try' block is around the line that sets the last contacted date only, so if, there is an error detected, we (as the programmer) know where it is. The catch segment gets passed the error from the application and it stores it in the parameter (err in this example) which we can then use.  You can use google to find out more about the error object created by the system and what’s available for you to use in your code, the two key things you may want to look at are: ‘name’ and ‘message’.

So now we know that we can put a fence (try) around parts of our code that might error.  Typically, I like to put them around pieces of code that I know will be an issue if there is a mistake or if there is something that could be influenced or changed later (like someone removing field that code updates, for example).  We’ve also seen that we can ‘catch’ the error and put up a nicer more meaningful message.  We can also put more code inside the catch block to do something else and this will only execute if there is an error that occurs inside the try block.  But wait there’s more!

Throw me something to work with

When we are working with a user and asking them to input data in a form, for example, they don’t always do what we want or expect them to do.  Lets say we have an unconstrained number field as an input, but for some reason we want them to enter a number between  5 and 10.    We can use the ‘throw’ to create an more elegant error message that is presented to the user.   Here below is an example of a how we’d use the ‘throw’ command.   I’ve taken this example directly from https://www.w3schools.com which by the way, is great resource to help you learn more about programming languages and their syntax.  I refer to their website all the time.


<!DOCTYPE html>
<html>
<body>
<p>Please input a number between 5 and 10:</p>
<input id="demo" type="text">
<button type="button" onclick="myFunction()">Test Input</button>
<p id="p01"></p>
<script>
function myFunction() {
  const message = document.getElementById("p01");
  message.innerHTML = "";
  let x = document.getElementById("demo").value;
  try {
    if(x.trim() == "") throw "empty";
    if(isNaN(x)) throw "not a number";
    x = Number(x);
    if(x < 5) throw "too low";
    if(x > 10) throw "too high";
  }
  catch(err) {
    message.innerHTML = "Input is " + err;
  }
}
</script>
</body>
</html>

Let’s look at how it works.  In the try block, you can see there are multiple ‘if’s and they are checking the value which has been entered by the user. At the end of the ‘if is the ‘throw’.  It is really just setting that error object we touched on a little while ago.  Depending on which ‘if’ gets activated, the error message in the ‘error’ object will be set to the value that is thrown.

Now we know how to do some simple form validation, verification, put a fence around potentially erroring creating code, and catch the error if one occurs, we  can even create our own custom messages too.

finally!

Isn’t it great!  We can check to see if in advance if we expect there may be an issue, we can verify what the fields on forms are (the type we expect),  we can put guards around the area that might create errors for things outside our control (and our syntax or spelling mistakes ) and we can make the messages to the user more palatable, but what we’d really like to do is ensure that the program continues to work and the user or the appropriate person gets what is expected and that the error can be dealt with appropriately.  This is where the final piece of the puzzle comes in, right at the end and it's the ‘finally’ clause.   With the ‘finally’ clause you can execute code after the try -catch regardless of the result.

 Here is our sample with the ‘finally’ clause added in.  For the purpose of this post we’re only going to raise another alert, but in the real world this where you would put the code that needed to run regardless of whether or not there was an error.  We don’t always need a finally clause, but its good practice to start using it as often as you can.

ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
      Var dateFld == formContext.getAttribute("new_lastcontactdate");
         if(null !== dateFld){
           
            var fldType == dateFld.getAttributeType();
            If (fldType == "datetime"){
               var now = new Date();
               try {
                  formContext.getAttribute("new_lastcontactdate").SETvalue(now);
              }
              Catch(err){// this is where we deal with any errors from the above try
                 alert(“There has been an error setting the date: ” + err);
              }
              Finally {
                  alert(“we’ve hit the finally clause, this will run after the try catch regardless”);
              }
            }
            else {
               return;
            }
         }
         else {
           return;
         }
   }
}

Summary

Defensive programming is all about doing our absolute best to elegantly handle the unexpected.    When using JavaScript for form manipulation in D365 for example, we first looked at how using a NameSpace can avoid the wrong function being called then we went on to look at how we can test to see if a field is there (by assigning the field to a variable and checking it’s not null) ,  then we looked at how to check it’s the right type of field (using the getAttributeType function) .  Next, we looked at how we can add guard rails around sections of code that might error (using the ‘try’ block).   We then looked at how we can handle errors that do happen (using the ‘catch’ block).   We even looked at how to create our own error messages (using the ‘throw’ function) and then how we can make sure that the ‘critical’ or ‘must always happen’ code still runs (using the 'finally’ clause). 

 We don’t need to use all these techniques all of the time, but they can be used with great effect to save us (and others) time and therefore money in the future.  The bigger a project gets, the more code you write, the more time consuming it becomes to find and fix errors, especially the ones that don’t present themselves consistently.  Avoiding crashes is ALWAYS better than trying to fix the aftermath…

 External references used – W3 Schools (https://www.w3schools.com/ )

Tuesday, March 18, 2025

JavaScript - Name Spaces and Defensive programming in D365 Pt 1

What is defensive Programming?  Pt1

When we write programs, we (normally) have a very clear idea of what it is we want to achieve, When we look at JavaScript form manipulation in D365 specifically,  we know which fields, sections and tabs we want to manipulate, whether it’s making a field Read-only or mandatory, based on the value of another field, or hiding whole sections or tabs based on a user’s login and security role and we write the scripts accordingly.  However, other people may have access to the system and may be doing updates of their own.   If those updates happen to change a field or tab name we rely on in our code, it could cause problems.   How we guard against adverse effects of these changes is referred to as ‘defensive programming’.  Let me give you a common definition of defensive programming from our friend Mr Google:

Defensive programming is a proactive approach to software development that focuses on anticipating potential problems and implementing safeguards to prevent crashes, bugs, and vulnerabilities, ensuring the application functions reliably even under unforeseen circumstances. 

This blog is not going to teach you how to write JavaScript, but I will show you some of the basic techniques we can use when manipulating forms or responding to events on a Form in d365.

Name Space

When we write programs, we as programmers talk about the scope of variables or the scope of a function in relation to other functions or libraries.  Namespacing is an extension of managing ‘Scope’ and refers to the provision of scope (think boundaries) around functions.  JavaScript files (Web Resources in D365) are read into memory and used when called by an event, typically on the form.  Let’s consider two functions, written by two separate developers housed in two separate libraries.

The first function is called ‘set date’ and sets the ‘Last Contact date on a contact record.  The library is called ‘ContactFormEvents.js’.  The purpose of this function is to set the value of a field on the form called ‘Last Contact date’ when the form is saved.

Here is a snippet of the code

Function setDate(executionContext)
   let formContext = executionContext.getFormContext();
   var now = new Date();
   formContext.getAttribute("new_lastcontactdate").setValue(now);
}

 

Now suppose we have another library called CommonFunctions.jS  that a helpful dev. has created to organise all the common functions in to one simple library, only this Dev. Has thought that it would be a great idea to set the next contact date to 1 month after the record has been saved.  They create the following function

Function setDate(executionContext)
   let formContext = executionContext.getFormContext();
   var now = new Date()
   var nextDate = now.setMonth(now.getMonth() + 1);
   formContext.getAttribute("new_nextcontactdate").setValue(nextDate);

Ok, I think you can see where this is going.  Lets suppose both libraries are added to the contact form.  The first developer attaches an event to the on save for the form

‘setDate’

Which one is going to run, which is it the one the developer wants to run?  Both are valid and both are loaded in to memory, oh dear.

Whilst this is an over simplification, the issue is more than valid and more common than you would want to believe.  Don’t worry, there is a real simple fix and its not that hard once you get your head around it.  Lets look at how we can use a NameSpace to ensure only the correct ‘setDate’ function is called.

How do we create a NameSpace?

There are a couple of ways, and this is how I do it:

if (typeof ContactEvents == "undefined") {
    ContactEvents = {};
}

Here I check to see if the namespace ‘ContactEvents’ has been defined and if not I create it.

This is what the updated code snippet could look like using the new namespace

if (typeof ContactEvents == "undefined") {
    ContactEvents = {};
}
ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
     var now = new Date();
      formContext.getAttribute("new_lastcontactdate").setValue(now);
   }
}

Now when I call the function in the on save event, I change the call to include the namespace so it looks like this:

ConactEvents.setDate

Now I know which function is being called.  Even if the common library doesn’t have a name space, but the contact form events library does, it means they won’t get mixed up.

Namespacing is only one component of defensive programming. The next one is 

Validation and Verification

If we assume that because we created the last contact field and we’ve added a namespaced function to update it, that everything is fine and dandy and we can have a nice pat on back while we drink our well earned coffee we could be in for a surprise.

Lets take the examples from above, and lets assume the our helpful second dev, has decided not only to add some useful functions, but they’ve also tidied up the form and created the last contacted filed with a slightly different name more in keeping with the rest of the naming used on the form.  Lets image the field has been recreated and is not called new_dateLastContacted, what happens to our function when its called.  BANG! It crashes and pops up some error message that confuses the user. Oh dear (again).

Don’t worry we can fix this too.  We interject a test, and a validation

First we check to see if the field is on the form we do this by grabbing the field by name and seeing if it there or not (null).  The following snippet tries to assign a field to the variable dateFld.  Then dateFld is compared to ‘null’ if it is null, it simply jumps out with no error

Var dateFld == formContext.getAttribute("new_lastcontactdate");
if(null !== dateFld){
}
Else {
   Return;
}
Now let’s verify the field that comes back is in fact a date field (as opposed to a text field for example)

   Var fldType == dateFld.getAttributeType();

   If (fldType == “datetime”){

   return true;

}

So now, we know how to ensure we call the right function, we know how to test in our function that the field is still on the form and that the field is the right (or expected) type, now we can execute knowing we have the correct function, the correct field and it’s of the right type.  Here is what the updated function could look like:

ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
      Var dateFld == formContext.getAttribute("new_lastcontactdate");
         if(null !== dateFld){
            var fldType == dateFld.getAttributeType();
            If (fldType == "datetime"){
               var now = new Date();
               formContext.getAttribute("new_lastcontactdate").setValue(now);
            }
            else {
               return;
            }
         }
         else {
           return;
         }
   }
}

There is another component to defensive programming and it’s about testing the actual execution steps within the function have executed correctly without error, in JavaScript we use a function wrapper called ‘Try Catch’.  I’ll save the explanation of what a try-catch is and how to use it for another blog but the simplistic explanation is as follows:

We add a block around the execution statement and if an error occurs it is trapped by the catch block, where we can then show it or do something else.

try {
  Execution Block
}
catch (error)
{
   Display or do something with the error information
}

There are a couple of more pieces with the try-catch, they are ‘throw’ and ‘finally’, but I’ll cover these when I cover try-catch in more detail.


Friday, March 14, 2025

 

Coupling and Cohesion or

When to create table relationship and when to use Connections.

What the… has Couple and Cohesion got to do with CRM I hear you ask.  Well, I’m glad you did.  Let’s start with a basic software engineering definition. 

Coupling refers to the degree of interdependence between modules and

Cohesion refers to the degree in which elements within a module work together to fulfill a single. Well defined purpose.

Ok, but what does that mean in relation to Dynamics CRM?  When we talk about Coupling in CRM, we are really talking about the number of relationships created between entities (Tables) and when we talk about cohesion, we are really talking about what we store in an entity or table.

Great, that’s cleared that up.  So, what does it really mean?  Let’s look at a simplified example.

The fictious car company, Better Faster Cars (BFC).  They manufacture and sell cars to global network of dealers.  In their organisation, the sales team is split up into various teams who all have a roll to play in feeding information back to the manufacturing team to help improve delivery schedules, quality improvements, feature improvements and more.  They also have a team of Quality engineers that also feed information back to the manufacturing team.  The Executives, take a keen interest in the profitability of BFC and they too, feed information back to the Manufacturing team to assist in streamlining the process.  The dealers, guess what, they too send information back to the Manufacturing team about service issues, warranty issues and customer feedback.  You get the idea.  There are lots of people and teams all taking to the Manufacturing team.

There are two ways we can model this in CRM.  We could map each of the user interactions with the Manufacturing team as a named relationship.  In the table below we’d have 14 separate table relationships between the user table and the manufacturing table

Dealer Sales Feedback (USER)

Many to one relationship

Manufacturing

Delivery Updates (User)

Many to one relationship

Manufacturing

Quality Sign Off Exterior (User)

Many to one relationship

Manufacturing

Quality Sign off Engine (User)

Many to one relationship

Manufacturing

Quality Sign off Interiors (User)

Many to one relationship

Manufacturing

Quality failure Notification (User)

Many to one relationship

Manufacturing

New Feature Request (user)

Many to one relationship

Manufacturing

New Model Request (User)

Many to one relationship

Manufacturing

Executive Sign off

Many to one relationship

Manufacturing

Executive budget sign off (user)

Many to one relationship

Manufacturing

Dealer Warranty Claim (User)

Many to one relationship

Manufacturing

Deal Model Spec Change Request (user)

Many to one relationship

Manufacturing

Exec team change request sign off (User)

Many to one relationship

Manufacturing

Exec Team Model change sign off (User)

Many to one relationship

Manufacturing

 On way to think of relationships between entities or tables is like doorways that you can pass information through, but you need to have a door for each type of information you want to pass through it or one door for each person who is going from one room to the other.  If we change the analogy slightly and think about rooms in different buildings and we use bus to move the individuals from room to room.  1 individual 1 bus.  Not the most efficient way to do it.  That’s not to say that it is wrong to do this.  There are other ways to do it, that are easier to manage, easier to read and do not require all those relationships to be created for every single record, regardless of if they are used or not. 

This method is known as Coupling, the higher the number of relationships the higher the coupling.

Side Note

We not going into the merits of software design here, merely trying to highlight the difference between to ways of implementing a solution.

CRM / D365 comes with a very neat feature called ‘Connections’ is a cleaver way to join entities, on the fly, without having to go and create your own set of entity relationships.  What’s more, you can join almost any entity with any other entity.  We can take advantage of this feature to simplify our model. 

Here’s how.  To use Connections, you first need to create some ‘Roles’.  A ‘Role’ is really the name of the relationship.  For example, we could create the following roles:

·         Approves Update Request

·         Requests Feature Update

·         Approves Feature

·         Requests Warranty approval

·         Approves Quality check

In order to use the connections, you’ll also need to add a table (sub grid) on the form of the entity you want to see them and set up some permissions and complete the configuration steps, but once you have then you can start adding the data as you have it.

To try and put that into context.  If you are entering the data on the manufacturing entity, you receive a request for a warranty claim, you go to the grid, click on add new connection,  select the user who (from) made the request,, select the connection type (role) for example  ‘Requests Warranty Approval’ and then add the some details in the description box and save it. As more requests or approvals come in you can add more connections.  Anyone viewing that record can easily see all the connections.

Now if we go back to the question, Relationships or Connections?  The answer depends, like always, on what you are trying to achieve.  I personally would suggest that if you have many relationships from to a two a single entity, it is a candidate for using connections.  Furthermore, Connections are great for when you want to join entities together for a given interaction or reason.  For example. If you have multiple companies that you are working with on a project and each company is providing a different service  and also provides the same or other services to other companies and projects,  building a set of relationships to capture all the potential combinations would be a nightmare, and messy!  But, if you use Connections, you only have to define the relationship roles then you can just select the two entities and select the role (what they do) that joins them.  Connections are particularly useful when you want to capture information about a contact who acts in different roles for different clients or projects.

Connections, if you haven’t guessed are more in line with Cohesion, because they take care of the relationship building inside a virtual black box that the user (designer) doesn’t have to worry about.

How to Create a PCF by Neeraj Agrawal

 I came across this great introduction to PCF controls today and rather than try to compete and write a similar post myself, I thought I...