SQL integration of Exchange and Salesforce

Peter Hanustiak Technical Leave a Comment

1. Topic

1.1 Introduction

Due to the success of our first technical article which can be found here we decided to continue. This time we will take a look at how an integration between Exchange and Salesforce can be achieved in a most simple way. We will use SQL queries.

For the integration we use CB Linked Server for Enterprise Applications. Ask us for a free trial of the product.

2. Scenario Requirements

The integration scenario required here is to synchronize between a local database contacts table, Exchange 365 contacts and SalesForce contacts and to have an immediate replication from the local database table to those 2 target systems. This could be useful to have a backup of contacts offline or to create a data warehouse or for some other reasons.

3. Basic Workflow

3.1 Configure CB Query Analyzer

First step, is to ensure that you are able to connect to the target system (Exchange & SalesForce in our scenario); easiest way to do that is via CB Query Analyzer. Here I already configured my ConnectBridge server via the Administration tool to connect to MS Exchange 365 and to SalesForce by creating the required groups and users. I created a username called “martin” with password “1234”. This user is having rights to connect to Exchange 365 and SalesForce. Now from Query Analyzer I will create 2 connections to each target system and ensure that I can connect successfully.

Figure 1: Accounts Administration

Figure 2: Group & User Administration

Figure 3: Query Analyzer Connections

3.2 Test your Statements

As shown above we have a successful configuration and connection to both target systems. Now we can test our statements

3.2.1 Exchange Contacts

On my Exchange account, I have 3 contacts as shown below

Figure 4: Exchange Contacts

Now we are going to test the 4 basic operations SELECT, INSERT, UPDATE & DELETE

1. Selecting contacts

Executing the below statement should give us the 3 contacts shown in Figure 5.

SELECT [GivenName],[SurName],[Email1EmailAddress] FROM [Contact];

Figure 5: Selecting Contacts

2. Inserting a contact

Executing the below statement should insert a new contact shown in Figure 6

INSERT INTO Contact([GivenName],[SurName],[Email1EmailAddress]) VALUES ('Peter','K.', 'peter@gmail.com');

Figure 6: Inserting New Contact

3. Updating a contact

Executing the below statement should update the last name of the contact we inserted earlier as shown in Figure 7

UPDATE Contact SET [SurName] = 'Keys' WHERE [Email1EmailAddress] LIKE 'peter@gmail.com';

Figure 7: Updating Contact

4. Deleting a contact

Executing the below statement should delete the newly inserted contact as shown in Figure 8

DELETE FROM Contact WHERE [Email1EmailAddress] LIKE 'peter@gmail.com';

Figure 8: Deleting Contact

3.2.2 Salesforce Contacts

On my SalesForce account, I have 17 contacts as shown below

Figure 9: SalesForce Contacts

Now we are going to test the same 4 basic operations SELECT, INSERT, UPDATE & DELETE.

1. Selecting contacts

Executing the below statement should give us the 17 contacts shown in Figure 10.

SELECT [FirstName],[LastName],[Email] FROM [Contact];

Figure 10: Selecting Contacts

2. Inserting a contact

Executing the below statement should insert a new contact shown in Figure 11

INSERT INTO Contact([Firstname],[LastName],[Email]) VALUES ('Peter','K.', 'peter@gmail.com');

Figure 11: Inserting New Contact

3. Updating a contact

Executing the below statement should update the last name of the contact we inserted earlier as shown in Figure 12

UPDATE Contact SET [LastName] = 'Keys' WHERE [Email] = 'peter@gmail.com';

Figure 12: Updating Contact

4. Deleting a contact

Executing the below statement should delete the newly inserted contact as shown in Figure 13

DELETE FROM Contact WHERE [Email] = 'peter@gmail.com';

Figure 13: Deleting Contact

3.3 Copy Connection and Statements

Now we know that we are able to select, update, insert and delete contacts from Exchange & SalesForce. What we need do now is to copy the connection string from Query Analyzer and our tested statements to use them later in our MS SQL Server Solution.

To copy the connection from query analyzer, we just need to right click the connection, click Edit and go to Advanced tab and copy the text from there as shown below in Figure 14.

Figure 14: Copying connection string from Query Analyzer

Here are my connection strings for both target systems.

Exchange

Driver={Media Gateway ODBC Driver};impl='CORBA';host='localhost';port='8087';acc='ACC_EXCH365_CU7';uid='martin';pwd='1234'

SalesForce

Driver={Media Gateway ODBC Driver};IMPL=CORBA;HOST='localhost';PORT='8087';ACC='ACC_SALF_CBD';UID='martin';PWD='1234'

Now we are ready to open MS SQL Server and start implement our SQL Server integration solution.

4. Solution Walkthrough

4.1 MS SQL Server

To be able to work with external data sources via SQL Server Linked Server feature, we need to do the following configurations

1. Start Microsoft SQL Server Management Studio and login using either windows authentication or username and password as shown below in Figure 15

Figure 15: MS SQL Server Management Studio Login Screen

Figure 16: MSDASQL Properties

2. Navigate to Sever Objects -> Linked Servers -> Providers -> MSDASQL by expanding the corresponding nodes as shown above in Figure 16. Right click on MSDASQL – Microsoft Data Access SQL – and select Properties to show the dialog in Figure 17

Figure 17: MSDASQL Properties Settings

3. We have to ensure that the following settings/options are checked:

a. Level zero only: For security reasons we have to ensure that only OLE DB providers that are compliant with level 0 OLE DB interface are supported.

b. Allow inprocess: to allow the data provider(s) – “external data sources” – to be instantiated as an in-process server – “in the same process as MS SQL Server”. We need to do that to avoid passing authentication information between MS SQL Server and the Provider and to be able to work with datatypes like (varchar(max), nvarchar(max), varbinary(max), text, ntext, or image). Without enabling this option, we won’t be able get a data of type image from Exchange – for example – and insert it in our MS SQL Server Database.

4. Now we need to enable MS SQL Server to connect to external providers and execute queries to query data from external providers that use OLEDB – let’s call them “External OLEDB Data Sources”. We will do that in 3 steps:

a. We need to open a new Query window by clicking the New Query button as shown in Figure 18 below. It doesn’t matter which database is active, because what we are going to do is going to affect the entire MS SQL Server installation and in turn each and every database in there. As show below I have “master” as the active/target database

Figure 18: MS SQL Server Query Analyzer

b. We need to reconfigure MS SQL Server so that we can change/configure its advanced options. To do that we are going to execute a stored procedure called “sp_configure” – it’s a preinstalled system stored procedure – and we are going to specifically “show advanced options” – by setting this option to 1. To do that we type “exec sp_configure ‘show advanced options’, 1; reconfigure” and press F5 to execute. If everything goes right, you should get a message similar to the message in Figure 19 below

Figure 19: MS SQL Server – Showing Advanced Options

c. Now we need to allow MS SQL Server to query those “External OLEDB Data Sources” using something called “Ad Hoc Distributed Queries”. By default, MS SQL Server doesn’t allow the “Ad Hoc Distributed Queries” therefore we need to reconfigure this advanced option – that’s why we did the previous step – by executing the stored procedure “sp_configure” passing the setting “Ad Hoc Distributed Queries” and the value 1 to enable it. If everything goes right, you should get a message similar to the message in Figure 20 below after executing “exec sp_configure ‘Ad Hoc Distributed Queries’, 1; reconfigure”

Figure 20: MS SQL Server – Enabling Ad Hoc Distributed Queries

Now we can add as many Linked Server as we want, since our MS SQL Server is properly configured to allow that.

4.2 Configuring MS Exchange Linked Server

1. Navigate to Sever Objects -> Linked Servers. Right click on Linked Servers and choose New Linked Server as shown in the Figure 21 below

Figure 21: MS SQL Server – Adding New Linked Server

2. In the new Linked Server dialog, as shown in Figure 22 below, you need to provide the following:

a. Linked Server name: could be any valid name, I choose Exchange365_CU7.

b. Provider: must be “Microsoft OLE DB Providers for ODBC Drivers”, as ConnectBridge is using ODBC.

c. Provider String: here we paste the connection string we copied earlier from query Analyzer.

Figure 22: MS SQL Server – Configuring New Linked Server – General

3.Now we need to establish a relationship between the user using/accessing MS SQL Server and the user using/accessing CB. The user using MS SQL Server is called Local Login (in our scenario it’s “sa”) and the user using/accessing CB is called Remote User (in our scenario it’s Martin with login martin). This is what we have to configure, and to do that we click “security” tab to show the dialog in Figure 23 below

Figure 23: MS SQL Server – Configuring New Linked Server – Security

4. When the above dialog is displayed, we click the Add button and we type in the Local Login and the Remote User as we agreed. That’s what I did here in Figure 24

Figure 24: MS SQL Server – Configuring New Linked Server – Logins

5. Okay I know you want to close the dialog but wait! we need to do one more step. Now we need to go to “Server Options” tab on the left hand side to show the dialog in Figure 25 below and enable 2 features

a. RPC: to enable a certain security feature which we would need when we use some legacy feature called Remote Server – don’t worry about it now – so that login validation between CB and MS SQL Server is possible

b. RPC Out: to enable “Remote Procedure Call” feature, as we need to allow our stored procedures to be able to run remotely

Figure 25: MS SQL Server – Configuring New Linked Server – Server Options

6. Now we click okay and we are done! Yes! We configured MS SQL Server to connect to Exchange. Now we can see Exchange platform as a database in MS SQL Server, we can see table called Contacts, we can show a list of contacts from Exchange, all this, without accessing Exchange database as you could see in Figure 26 below

Figure 26: MS SQL Server – Linked Server Configured Successfully

4.3 Testing MS Exchange Linked Server

Before developing our integration solution, we need to be sure that we are able to perform the Basic Data manipulation on MS Exchange via our newly configured Linked Server.

1. Selecting contacts

Executing the below statement should give us the 3 contacts from MS Exchange.

SELECT GivenName, SurName, Email1EmailAddress FROM EXCHANGE365_CU7...Contact;

Why the “…”? Because it follows the syntax SERVER.DATABASE.SCHEMA.TABLE and as you could see from Figure 26 above, our Server is Exchange365_CU7, our database is “without name” our schema is “without name” and finally our table is Contacts.

Figure 27: Selecting Contacts

2. Inserting a contact

Executing the below statement should insert a new contact.

EXEC ('INSERT INTO Contact([GivenName], [SurName], [Email1EmailAddress])
VALUES ("Peter", "K.", "peter@gmail.com");') AT EXCHANGE365_CU7;

Figure 28: Inserting New Contact

3. Updating a contact

Executing the below statement should update the last name of the contact we inserted earlier

EXEC('UPDATE Contact SET [SurName] = "Keys" WHERE [Email1EmailAddress] LIKE
"peter@gmail.com";') AT EXCHANGE365_CU7;

Figure 29: Updating Contact

4. Deleting a contact

Executing the below statement should delete the newly inserted contact

EXEC ('DELETE FROM Contact WHERE [Email1EmailAddress] LIKE
"peter@gmail.com";') AT EXCHANGE365_CU7;

Figure 30: Deleting Contact

4.4 Configuring SalesForce Linked Server

We are going to follow the steps from section “4.2 Configuring MS Exchange Linked Server” except of course we are going to use the Connection String for SalesForce. After following those steps, your Linked Server should be configured successfully as shown below.

Figure 31: SalesForce Linked Server Configured Successfully

4.5 Testing Salesforce Linked Server

As we did before also with MS Exchange Linked Server, we need to ensure that we are able to perform the Basic Data Manipulation tasks via the SalesForce Linked Server.

For shorten the guide, Figure 32 below is testing all the following statements

1. Selecting contacts

Executing the below statement should give us the contacts from SalesForce.

SELECT GivenName, SurName, Email1EmailAddress FROM EXCHANGE365_CU7...Contact;

2. Inserting a contact

Executing the below statement should insert a new contact.

EXEC ('INSERT INTO Contact([GivenName], [SurName], [Email1EmailAddress])
VALUES ("Peter", "K.", "peter@gmail.com");') AT EXCHANGE365_CU7;

3. Updating a contact

Executing the below statement should update the last name of the contact we inserted earlier

EXEC('UPDATE Contact SET [SurName] = "Keys" WHERE [Email1EmailAddress] LIKE
"peter@gmail.com";') AT EXCHANGE365_CU7;

4. Deleting a contact

Executing the below statement should delete the newly inserted contact

EXEC ('DELETE FROM Contact WHERE [Email1EmailAddress] LIKE
"peter@gmail.com";') AT EXCHANGE365_CU7;

Figure 32: Testing SalesForce Linked Server

4.6 Local Database table

From here, we need to have an actual local database on our Local MS SQL Server. If you already have one, then you could use otherwise we need to create a new Database. I created a Database called ConnectingSoftware with 1 table called LocalContacts. In that table there is only one record as shown below in Figure 33.

Figure 33: Local Contacts Table

4.7 Replication Table trigger

The first step in our solution is to replicate the changes in our Local database table to both SalesForce and Exchange. we are going to implement this via table trigger.

SQL Script for the trigger is shown below:

CREATE TRIGGER [dbo].[trgSyncContact]
ON [dbo].[LocalContacts]
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
declare @Operation varchar(50)
declare @FirstName nvarchar(max)
declare @LastName nvarchar(max)
declare @Email varchar(255)
declare @Deleted_FirstName nvarchar(max)
declare @Deleted_LastName nvarchar(max)
declare @Deleted_Email varchar(255)

IF COLUMNS_UPDATED() > 0
BEGIN
--if we have updated columns, then we either inserted or deleted a
record
IF EXISTS (SELECT * FROM DELETED)
BEGIN
--if we have deleted values, then it was an update operation
SELECT @FirstName = inserted.FirstName, @LastName =
inserted.LastName, @Email = inserted.Email,
@Deleted_FirstName = deleted.FirstName,
@Deleted_LastName = deleted.LastName, @Deleted_Email =
deleted.Email
FROM deleted, inserted
--SalesForce
Exec ('UPDATE Contact SET FirstName = ?, LastName = ?, Email = ?
WHERE FirstName = ? and LastName = ? and Email = ?',
@FirstName, @LastName, @Email, @Deleted_FirstName,
@Deleted_LastName, @Deleted_Email) at SALESFORCE_CBD;
--Exchange
EXEC ('UPDATE Contact SET GivenName = ?, SurName = ?,
Email1EmailAddress = ? WHERE GivenName = ? and SurName =
? and Email1EmailAddress = ?', @FirstName, @LastName,
@Email, @Deleted_FirstName, @Deleted_LastName,
@Deleted_Email) at EXCHANGE365_CU7;
END
ELSE
BEGIN
--if it wasn't update operation, then it was insert
SELECT @FirstName = FirstName, @LastName = LastName, @Email =
Email
FROM inserted
--SalesForce
Exec ('Insert into Contact (FirstName, LastName, Email) values
(?,?,?)', @FirstName, @LastName, @Email) at
SALESFORCE_CBD;
--MS Exchange
EXEC ('Insert into Contact (GivenName, SurName,
Email1EmailAddress) values(?,?,?)', @FirstName,
@LastName, @Email) at EXCHANGE365_CU7;
END
END
ELSE
BEGIN
--if the operation was not update/insert then it was delete
SELECT @Deleted_Email = Email FROM deleted
--SalesForce
Exec ('Delete From Contact Where Email = ?', @Deleted_Email) at
SALESFORCE_CBD;
--MS Exchange
Exec ('Delete From Contact Where Email1EmailAddress = ?',
@Deleted_Email) at EXCHANGE365_CU7;
END
END

Warning: after executing the above script, we shouldn’t insert anything from the local database table until we synchronize between our 2 target systems (Exchange and SalesForce) and our Local database, otherwise we could end up in accidentally duplicating records since the logic here doesn’t check if a new record already existed on those target systems.

4.8 Synchronization Stored Procedure

The second step in our solution is to synchronize between MS Exchange, SalesForce and our Local Contacts table, so that each system will have the same set of contacts.

To do that we are going to write a stored procedure. The logic of the procedure is to:

1. Very important to disable the trigger we created above “as we are doing the synchronization, we must not enable the automatic replication implemented by the trigger”

2. Synchronize between SalesForce & my database
Using contact’s email address as a matching key; Is there a contact on SalesForce and not in my Local Contacts table?

a. Yes: Add contact to my Local Contacts Table

b. No: Update contact’s First Name and Last Name in my Local Contacts Table

3. Synchronize between MS Exchange & my database
Using contact’s email address as a matching key; Is there a contact on Exchange and not in my Local Contacts table?

a. Yes: Add contact to my Local Contacts Table

b. No: Update contact’s First Name and Last Name in my Local Contacts Table

At this point, my local Contacts table is having all contacts from both SalesForce and MS Exchange in addition to the records that were originally in the table. Now we need to update each target system by the contacts from the other target system and the Local database

4. Update contacts on SalesForce (by contacts from Exchange & my local table)

Using contact’s email address as a matching key; Is there a contact in my Local Contacts table and not on SalesForce?

a. Yes: Add contact to SalesForce

b. No: Update contact’s First Name and Last Name on SalesForce

5. Update contacts on Exchange (by contacts from SalesForce & my local table)

Using contact’s email address as a matching key; Is there a contact in my Local Contacts table and not on Exchange?

a. Yes: Add contact to MS Exchange

b. No: Update contact’s First Name and Last Name on Exchange

6. Now, we can enable the trigger we disabled earlier, so the automatic replication is back ON.

The following SQL script will implement the logic discussed above

CREATE PROCEDURE [dbo].[uspInitSync]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

--disable trigger so that, while inserting from SalesForce we don't endup in
--adding the contacts again to SalesForce
DISABLE TRIGGER [trgSyncContact] ON LocalContacts;

--merge records from SalesForce to LocalDB
DECLARE @ImportedContacts Table(FirstName nvarchar(max), LastName
nvarchar(max), Email varchar(255));

--update / insert contacts in LocalDB using SalesForce as source
MERGE LocalContacts AS target
USING (SELECT FirstName, LastName, Email FROM SalesForce_CBD...Contact)
AS source
ON (target.Email LIKE source.Email)
WHEN MATCHED THEN
UPDATE SET FirstName = source.FirstName, LastName =
source.LastName
WHEN NOT MATCHED THEN
INSERT (FirstName, LastName, Email)
VALUES (source.FirstName, source.LastName, source.Email)
OUTPUT inserted.FirstName, inserted.LastName, inserted.Email
INTO @ImportedContacts;

--show inserted contacts in LocalDB from SalesForce
select * from @ImportedContacts;

--update / insert contacts in LocalDB using Exchange as source
MERGE LocalContacts AS target
USING (SELECT GivenName, SurName, Email1EmailAddress FROM
EXCHANGE365_CU7...Contact) AS source
ON (target.Email LIKE source.Email1EmailAddress)
WHEN MATCHED THEN
UPDATE SET FirstName = source.GivenName, LastName =
source.SurName
WHEN NOT MATCHED THEN
INSERT (FirstName, LastName, Email)
VALUES (source.GivenName, source.SurName,
source.Email1EmailAddress)
OUTPUT inserted.FirstName, inserted.LastName, inserted.Email
INTO @ImportedContacts;

--display inserted contacts using table variable
select * from @ImportedContacts;

--now copy everything to SalesForce & Exchange so they will have exact copy
--from LocalDB after LocalDB is sync with all systems
--I have to use cursour and if because using insert....select....where not
--exists didn't work with remote tables and also merge doesn't work with
--remote tables
Declare @FirstName nvarchar(max)
declare @LastName nvarchar(max)
declare @Email varchar(255)
declare @SQL nvarchar(max)

DECLARE Contacts_cursor CURSOR FAST_FORWARD FOR
SELECT FirstName, LastName, Email from LocalContacts;

OPEN Contacts_cursor
FETCH NEXT FROM Contacts_cursor INTO @FirstName, @LastName, @Email
WHILE @@FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT Email1EmailAddress FROM EXCHANGE365_CU7...Contact
WHERE Email1EmailAddress LIKE @Email)
EXEC ('UPDATE Contact SET GivenName = ?, SurName = ? WHERE
Email1EmailAddress = ?', @FirstName, @LastName, @Email)
at EXCHANGE365_CU7;
ELSE
EXEC ('Insert into Contact (GivenName, SurName,
Email1EmailAddress) values(?,?,?)', @FirstName,
@LastName, @Email) at EXCHANGE365_CU7;

IF EXISTS (SELECT Email FROM SalesForce_CBD...Contact WHERE Email LIKE
@Email)
Exec ('UPDATE Contact SET FirstName = ?, LastName = ? WHERE
Email = ?', @FirstName, @LastName, @Email) at
SalesForce_CBD;
ELSE
Exec ('Insert into Contact (FirstName, LastName, Email) values
(?,?,?)', @FirstName, @LastName, @Email) at
SalesForce_CBD;

FETCH NEXT FROM Contacts_cursor INTO @FirstName, @LastName, @Email
END
CLOSE Contacts_cursor;
DEALLOCATE Contacts_cursor;

--enable trigger so that any modification is reflected in online LOB
ENABLE TRIGGER [trgSyncContact] ON LocalContacts;
END

5. Solution in Action

Now first step is to run the synchronization stored procedure “uspInitSync” as shown below, the stored procedure was executed without errors.

Figure 34: running the synchronization stored procedure

We could also see that there were new contacts added to MS Exchange

Figure 35: Updates on MS Exchange

And new contacts added to SalesForce

Figure 36: Updates on SalesForce

And our local database table now is having new contacts

Figure 37: Updates in Local Contacts table

We can see the automatic replication in action as well

1. Inserting contact from local database, deletes it from SalesForce and Exchange

Figure 38: Insert Replication

2. Updating contact in local database updates it in SalesForce and Exchange

Figure 39: Update Replication

3. Deleting contact from local database, deletes it from SalesForce and Exchange

Figure 40: Delete Replication

6. Notes on Solution

We tried to keep the solution logic as much simple as possible, however the logic could be further improved & tweaked for better performance and more complex features.

You can find more info about this product on the product page of CB Linked Server для корпоративных приложений.

Share this Post

Добавить комментарий