I had a requirement where I need to generate a new unique id every time when a new record is inserted into the system. In such cases Script Component is very useful.
We can find Script Component under SSIS toolbox.
Now, going to Script Transformation Editor there we need to create a new column where we can create and store the newly generated ID.
Step 1: Click on Inputs and Outputs Step 2: Click on Add Columns Step 3: Name the column Step 4: Select the required data type.
Figure 1: Script Component Editor (Create new column)
Select the datatype as GUID for generating unique ID.
Next, we need to go to Script and hit Edit Script.. button.
Figure 2: Edit Script for writing custom code
This will open a project where we need to write a line of code for generating new GUID.
public override void Input0_ProcessInputRow(Input0Buffer Row) { Row.UniqueID = System.Guid.NewGuid(); }
Code for generating new GUID
Go to Input0_ProcessInputRow(Input0Buffer Row) method, under that write a line of code for generation of GUID.
Row.UniqueID = System.Guid.NewGuid();
That’s all we need to do for creating a new GUID, when a record is inserted into the destination system.
KingswaySoft provide us a Dynamics CRM OptionSet Mapping component under Common tab which lies inside SSIS toolbox. This component ease the data migration activity.
Figure 1: Optionset Mapping component
In my case, I haven’t used the Dynamics CRM OptionSet Mapping component. Reason the optionset mapping component didn’t populated the attributes which were of int type under Input Column field.
Figure 2: Optionset Mapping Input Column
Therefore we need to used Data Conversion and Derived Column components.
Assuming, Role is the name of option set attribute. So, under Data Conversion transformation editor we need to change the data type from int to string.
Select the Role attribute under Input Column, system will auto populate Copy of attribute name. In our case it will be “Copy of Role”, select the data type as Unicode string[DT_WSTR] and provide the length of the field as per your requirement. This Data Conversion transformation editor can be used for any attribute data type conversion.
Figure 3: Attributes Data type conversion.
Now, coming to Derived Column component. Here we need to create an expression for mapping the optionset label and value.
Figure 4: Mapping Optionset Label and Value
Expression used for OptionSet Mapping, if any of the option value is not found while data transmission then the system would enter “Not Found”.
Role == 954660008 ? "Participating Person" : Role == 954660004 ? "Overlay Sales" : Role == 954660000 ? "Account Manager" : Role == 954660001 ? "Sales Reporting Manager" : Role == 954660002 ? "Vertical Head" : Role == 954660003 ? "Geo Head" : Role == 954660005 ? "Co-Owners" : Role == 954660006 ? "Service Offering Lead" : Role == 954660007 ? "Horizontal Head" : "Not Found"
There are multiple expression under Derived Column component which are very use full and can be used as needed such as Mathematical Function(like LOG, ROUND, SQUARE etc), String Function (like TRIM, LTRIM, RTRIM, REVERSE, REPLACE, UPPER, LOWER etc), Date/Time Functions (like DAY, MONTH, YEAR, DATEDIFF etc), NULL Functions(like REPLACE NULL, etc), Type Casts, Operators(like ADD, SUBTRACT, MULTIPLY, DIVIDE etc.)
KingswaySoft is a tool which helps us in data migration activity.
Why Choose KingswaySoft for data migration?
User friendly UI: KingswaySoft has a very nice and easy to understand user interface. As, I was totally new with KingswaySoft tool. The UI really helped me during the data migration process as I need not struggled much by navigating here and there for searching an option.
Establishing connection between two difference system was pretty easy using connection managers. Not even a single line of code was required. If you have worked before on SSIS then KingswaySoft would be very simple.
Let jump to the scenario where I used Kingswaysoft tool.
I had to migrate date from Microsoft Dynamics 365 to Third Party application SQL(OLE DB Destination) database. In our case CRM was acting as an up stream system.
Figure 1: Data flow diagram.
Attached is the data flow diagram.
We will not go into very basic like how to establish connections using Connection Managers.
Figure 2: Screenshot of Dynamics CRM Source
Build a fetchxml with the required data/columns which needs to be inserted in the destination system. For me to push the desired data in destination I need to use source type as FetchXML.
Use of Data Conversion: This is used for conversion of an attribute data type like if the source system has an attribute of int type and the destination have the same attribute column in nvarchar datatype.
Use of Derived Column: This is where we can use multiple expression on our columns and populated the values in the destination table columns.
Expression which we can use are like:
Mathematical Functions, String Functions, Date/Time Functions, NULL Functions, Type Casts and Operators.
For attribute which are of option set type I needed to convert the int values into string format because the destination table column was of string type. Therefore I used Data Conversion.
Use of Script Component: This was used by me for creating unique id. When a new row gets inserted into destination table then generate a unique guid for each row..
OLE DB Destination: This is where we establish the connection with the destination system database. Mapping the Source System columns with Destination System columns.
I still see many people have some issue in understanding/calling namespace Javascript function.
Below pattern is a simple way of writing a Javascript in Dyanmics CRM, which most of the people are familiar with:
function MessagePopUp(executionContext)
{
var formContext = executionContext.getFormContext();
var email = formContext.getAttribute('emailaddress1').getValue();
alert('Welcome mail sent to ' + email);
}
Now, the namespace format, which is recommended by Microsoft. To avoid conflict within the functions name.
var Namespace = window.Namespace || {};
(
function (){
this.formOnLoad = function(executionContext)
{
var formContext = executionContext.getFormContext();
var email = formContext.getAttribute('emailaddress1').getValue();
alert('Welcome mail sent to ' + email);
}
}
).call(Namespace);
In the above code we have declared the variable as “Namespace”. The same should be called at the end of the function as .call(Namespace).
this.functionName = function(executionContext) /* In namespace notation javascript function should be called using this keyword, */
For calling a above namespace notation javascript, we need to call it as Namespace.formOnLoad on the event handler.
Figure 1: For calling formOnLoad function we need to use Namespace.formOnLoad Figure 2: Screenshot from Event Handlers
Save and Publish the code.
Refreshing the contact entity page and we will get the message pop-up on form onload.
Figure 3: Message Pop-Up
Hope this blog help in understanding Namespace Notation Javascript!!
Images are useful for data comparison before and after core operation. We can register plugins on two type of images:
Pre-Image
Post-Image
Pre-Image can be used for retrieving the value of an entity attribute before core operation takes place. Post-Image can be used for retrieving the value of an entity attribute after the core operation has taken place.
Scenario: On contact entity we have email address field. Let’s stop users from updating the email address field by showing them the old and new values.
using System; using Microsoft.Xrm.Sdk;
namespace HelloPlugin { public class PreImagePlugin: IPlugin { public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Get a reference to the Organization service. IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = factory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity) { Entity entity = (Entity)context.InputParameters["Target"];
try { //Implement Plugin Business Logic here string newemailaddress = string.Empty;
if (entity.Attributes.Contains("emailaddress1")) { newemailaddress = entity.Attributes["emailaddress1"].ToString(); }
Entity preImageContact = (Entity)context.PreEntityImages["PreImage"]; //PreImage is user defined name you can name anything.
string oldemailaddr = preImageContact.Attributes["emailaddress1"].ToString(); //preImageContact will provide us the value which was saved before the update event.
throw new InvalidPluginExecutionException("The email address is modified from " + oldemailaddr + " to " + newemailaddress); } catch (Exception ex) { throw new InvalidPluginExecutionException(ex.Message); } } } } }
Below is the screenshot of the exception message thrown by our plugin:
Figure 1: Populating email address using pre-image
Today we will learn how to restrict users from entering duplicate value in MS Dynamics CRM.
Let’s take as an example of Contact entity where we need to restrict users from entering duplicate email address which is already present in CRM while creating or updating a contact record.
I know there would a thought in your mind why don’t we use Duplicate Detection rule instead of plugin. So the answer to this question is duplicate detection rule will give user a warning message about the presence of duplicate record but still user will have the ability to ignore the warning message and save the record. Therefore, plugin is required for restricting users from entering duplicate records.
Note*: Below are the different techniques using which we can retrieve records. In this plugin we will be using Query Expression.
Fetch XML
Using Retrieve
Query Expression
Query By Attribute
LINQ
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace HelloPlugin
{
public class DuplicateCheck: IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Get a reference to the Organization service.
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
//Obtain the target entity from the input parameter
Entity contact = (Entity)context.InputParameters["Target"];
try
{
//Implement Plugin Business Logic here
string email = string.Empty; //Variable declared to check whether emailaddress field is empty or not.
if (contact.Attributes.Contains("emailaddress1"))
{
email = contact.Attributes["emailaddress1"].ToString();
QueryExpression query = new QueryExpression("contact");
query.ColumnSet = new ColumnSet(new string[] { "emailaddress1" });
query.Criteria.AddCondition("emailaddress1", ConditionOperator.Equal, email);
EntityCollection collection = service.RetrieveMultiple(query);
if (collection.Entities.Count > 0) //Check if any record is present with duplicate email address
{
throw new InvalidPluginExecutionException("Contact with email already exist");
}
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
}
}
}
}
Points to Remember for registering the plugin. Add two steps one for create contact another for update contact.
Create a follow up Task on create of Contact. The task should be completed in 2 days from the contact created on date.
Register the Plugin
on:
Message = Create
Primary Entity = contact
Pipeline Event = PostOperation
using System;
using Microsoft.Xrm.Sdk;
namespace HelloPlugin
{
public class CreateTask: IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Get a reference to the Organization service.
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
//Obtain the target entity from the input parameter
Entity contact = (Entity)context.InputParameters["Target"];
try{
//Implement Plugin Business Logic inside try block
Entity taskRecord = new Entity("task"); //Creating object taskRecord of task entity.
//Single line of text(String fields)Append Follow Up on Task entity Subject field
taskRecord.Attributes.Add("subject", "Follow Up");
//Append Need to follow up with contact statement on Task entity description field
taskRecord.Attributes.Add("description", "Need to follow up with contact");
//Set value in Date field
taskRecord.Attributes.Add("scheduledend", DateTime.Now.AddDays(2)); //Added 2 days from the Contact creation date.
//Set value in Optionset field (use Optionset value not lable)
taskRecord.Attributes.Add("prioritycode", new OptionSetValue(2));
//Set Parent Record to Task record.
//taskRecord.Attributes.Add("regardingobjectid", new EntityReference("contact", contact.Id)); //Old Methodology
taskRecord.Attributes.Add("regardingobjectid", contact.ToEntityReference());//New Methodology -- Link to Contact Record.
//Create a task record
Guid taskGuid = service.Create(taskRecord);
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
}
}
}
}
Figure 1: On create of Contact, follow up task got automatically created.
Today I went through an issue where I had a custom security role (Business Admin) having almost the same privilege as system admin user expect the update permission on custom master entities.
Issue: When user having Business Admin role was trying to assign security roles to other users then suddenly a message popped up on screen as permission issue.
RoleService::VerifyCallerPrivileges failed. User: a52a0940-6fde-e811-a96a-000d3af05828, PrivilegeName: prvReadOfficeGraphDocument, PrivilegeId: 39016011-ae1a-41d1-9a22-a2611ad16702, Depth: Global, BusinessUnitId: be4a982d-8cd0-e811-a964-000d3af05df5 If you contact support, please provide the technical details.
Reading the above message it is clearly state that read privilege needs to be provided on OfficeGraphDocument entity. But The entity is not visible on the security role form therefore the system admin user cannot go ahead and provide the permission
While investigating on the issue I found that Office Graph integration for Dynamics 365 for Customer Engagement apps was deprecated on August 31, 2017, at the same time that Office ends GQL query support. Customers can continue to use Office Graph integration through August 31, 2017. After August 31 that date, the Office Graph trending documents component will cease to function, and you’ll see the following error message:
We can’t get to the trending documents. Try again later.
When Microsoft Teams Integration is enabled, to get the Collaborate button appears on records in Dynamics 365 for Customer Engagement apps. We need to Enable Dynamics 365 and Teams Integration from System Settings.
Login to Dynamics CRM:
Go to Settings > Administration > System Settings > General tab
Enable Microsoft Teams Integration
Figure 8: Enable Microsoft Teams Integration – Collaborate button