Menu
D365
P L A Y T I M E
D365
P L A Y T I M E

A Custom Workflow Step For Duplicate Detection

Posted on September 13, 2019June 24, 2020

Duplicate detection is useful, but it doesn’t work in all scenarios. The one I constantly hit is cases where a record is being generated automatically via workflow or SDK, you won’t get Microsoft’s out of the box warnings or blocks in this instance.

Below is an example C# Custom Workflow Step that can be modified as per the requirement for identifying duplicates, a simple implementation using this would be to use a synchronous workflow running this check on create (or update) and cancelling if a duplicate is found preventing the entire operation from completing.

In this example we are checking to see if a contact already exists the requested email address associated with a specific account with the workflow triggering off of contact. Full code is at bottom of page if you just want to copy paste and play, I’ll outline the duplicate detectiony bits first below:

Inputs / Outputs

We’ll ask for an account reference, the email address we want to search against and confirm we’re gonna give a bool result back


[Input("Account")]
[ReferenceTarget("Account")]
public InArgument AccountInput { get; set; }

[Input("Email")]
public InArgument Email { get; set; }

[Output("Result")]
public OutArgument Result { get; set; }

Assign inputs and run methods

A bit back to front, we’ll assign the inputs and the record of the entity the workflow was triggered off and then assign the ouptut as the result of our method “CheckDupes”


erAccount = AccountInput.Get(executionContext);
sEmail = Email.Get(executionContext);
Guid RecordId = context.PrimaryEntityId;
bOutcome = CheckDupes(RecordId);
Result.Set(executionContext, bOutcome);

CheckDupes Method

So the Check Dupes method below runs another method (GetContacts), CheckDupes will pass the variables to GetContacts and get an entity collection back, if we get 0 results then we know there is no duplicate and set the response to false.


    private Boolean CheckDupes(Guid RecordId)
    {
        Boolean bResult = false;
        EntityCollection ecContacts = GetContacts(erAccount, sEmail, RecordId);
        if (ecContacts.Entities.Count == 0)
        {
            bResult = false;
        }
        else
        {
            bResult = true;
        }
        return bResult;
    }

CheckContact Method

The last method uses the variables it’s been passed to run a query in the CRM, return contacts with the specified email address associated with the specified account that are not the contact the workflow was triggered off


    private EntityCollection GetContacts(EntityReference vAccount, String vEmail, Guid RecordId)
    {
        EntityCollection ecResults = null;
        ColumnSet colContact = new ColumnSet();
        colContact.AddColumns("parentcustomerid", "emailaddress1");

        QueryExpression qryContacts = new QueryExpression()
        {
            EntityName = "contact",
            ColumnSet = colContact
        };

        FilterExpression filMaster = new FilterExpression(LogicalOperator.And);

        ConditionExpression conRecord = null;
        conRecord = new ConditionExpression()
        {
            AttributeName = "contactid",
            Operator = ConditionOperator.NotEqual,
            Values = { RecordId }
        };
        filMaster.AddCondition(conRecord);

        ConditionExpression conAccount = null;
        conAccount = new ConditionExpression()
        {
            AttributeName = "parentcustomerid",
            Operator = ConditionOperator.Equal,
            Values = { vAccount.Id }
        };
        filMaster.AddCondition(conAccount);

        ConditionExpression conEmailaddress = null;
        conEmailaddress = new ConditionExpression()
        {
            AttributeName = "emailaddress1",
            Operator = ConditionOperator.Equal,
            Values = { vEmail }
        };
        filMaster.AddCondition(conEmailaddress);


        qryContacts.Criteria.AddFilter(filMaster);
        qryContacts.Criteria.FilterOperator = LogicalOperator.And;
        ecResults = svcCRM.RetrieveMultiple(qryContacts);
        return ecResults;
    }

Full code


using System;
using System.Globalization;
using System.ServiceModel;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk.Query;

namespace DuplicateDetection.Example
{
public sealed partial class ContactEmailDupe : CodeActivity
{
    [Input("Account")]
    [ReferenceTarget("Account")]
    public InArgument AccountInput { get; set; }

    [Input("Email")]
    public InArgument Email { get; set; }

    [Output("Result")]
    public OutArgument Result { get; set; }

    IOrganizationService svcCRM;
    EntityReference erAccount;
    String sEmail;
    Boolean bOutcome = false;


    public sealed class LocalWorkflowContext
    {
        internal IServiceProvider ServiceProvider
        {
            get;

            private set;
        }

        internal IOrganizationService OrganizationService
        {
            get;

            private set;
        }

        internal IWorkflowContext WorkflowExecutionContext
        {
            get;

            private set;
        }


        
        internal LocalWorkflowContext(CodeActivityContext executionContext)
        {
            if (executionContext == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

        }

    }


    protected override void Execute(CodeActivityContext executionContext)
    {
        if (executionContext == null)
        {
            throw new ArgumentNullException("serviceProvider");
        }

        LocalWorkflowContext localcontext = new LocalWorkflowContext(executionContext);

            IWorkflowContext context = executionContext.GetExtension();

            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)executionContext.GetExtension();

            IOrganizationService OrganizationService = factory.CreateOrganizationService(context.UserId);
            svcCRM = OrganizationService;

            erAccount = AccountInput.Get(executionContext);
            sEmail = Email.Get(executionContext);
            Guid RecordId = context.PrimaryEntityId;
            bOutcome = CheckDupes(RecordId);
            Result.Set(executionContext, bOutcome);
  
    }


    private Boolean CheckDupes(Guid RecordId)
    {
        Boolean bResult = false;
        EntityCollection ecContacts = GetContacts(erAccount, sEmail, RecordId);

        if (ecContacts.Entities.Count == 0)
        {
            bResult = false;
        }
        else
        {
            bResult = true;
        }
        return bResult;
    }



    private EntityCollection GetContacts(EntityReference vAccount, String vEmail, Guid RecordId)
    {
        EntityCollection ecResults = null;
        ColumnSet colContact = new ColumnSet();
        colContact.AddColumns("parentcustomerid", "emailaddress1");

        QueryExpression qryContacts = new QueryExpression()
        {
            EntityName = "contact",
            ColumnSet = colContact
        };

        FilterExpression filMaster = new FilterExpression(LogicalOperator.And);

        ConditionExpression conRecord = null;
        conRecord = new ConditionExpression()
        {
            AttributeName = "contactid",
            Operator = ConditionOperator.NotEqual,
            Values = { RecordId }
        };
        filMaster.AddCondition(conRecord);

        ConditionExpression conAccount = null;
        conAccount = new ConditionExpression()
        {
            AttributeName = "parentcustomerid",
            Operator = ConditionOperator.Equal,
            Values = { vAccount.Id }
        };
        filMaster.AddCondition(conAccount);

        ConditionExpression conEmailaddress = null;
        conEmailaddress = new ConditionExpression()
        {
            AttributeName = "emailaddress1",
            Operator = ConditionOperator.Equal,
            Values = { vEmail }
        };
        filMaster.AddCondition(conEmailaddress);


        qryContacts.Criteria.AddFilter(filMaster);
        qryContacts.Criteria.FilterOperator = LogicalOperator.And;
        ecResults = svcCRM.RetrieveMultiple(qryContacts);
        return ecResults;
    }
}
}

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Retrieve the GUID of a record or Entity Reference within a workflow
  • How to find workflows that run a particular child workflow
  • Error when adding an Entity into Data Export Service that has been included before
  • How to sum / roll up rollup fields
  • Custom Workflow Step to calculate age

Recent Comments

    Archives

    • December 2020
    • June 2020
    • March 2020
    • October 2019
    • September 2019
    • July 2019
    • May 2019
    • March 2019
    • January 2019

    Categories

    • Custom Workflows
    • Data Export Service
    • dotmailer-connector
    • Dynamics Portal
    • Jquery/JS
    • UUI
    • Workflows
    ©2021 Dynamics 365 Playtime