Sunday 26 April 2015

Import Case, Account, and Contact (Multiple Entities–3 Entities ) at Once in Single File in CRM Import Wizard

In my previous post, I was talking about how to solve the unresolved lookup reference between primary entity and child entity which I Put Customer and Case as the entities.

Now, what if I want to import them at once.

A Case reference to a Contact that Parent Company is an Account, which is Primary Contact is the Contact itself.

So it is a chicken and egg circuit, circle round and always in the loop.

Now, prepare your data map

*You can get your simple sample data map by importing to CRM and make sure you map all fields correctly and then save and download your newly create data map

image

#0 Prepare the Source File

You can prepare the source file first then you can try to import to CRM to help you to create the Data Map and do mapping from your source to the CRM Target Entity and Attribute.

image

#1 Create New Custom Data Map or Use the Existing One and Download It

*As mentioned before you can use the existing data map and modify it.
If you noticed, you can learn how to create new data map from the ‘For Generic Contact and Account Data’

http://blogs.msdn.com/b/crm/archive/2010/11/04/importing-two-or-more-entities-from-a-single-file.aspx

And here our objective is to import 3 entities so that we need to create new Data Map.

#2 Edit the Data Map XML

Here is the XML of the data map:

<Map Name="Case Single File with Account and Contact Reference" Source="Import">
  <Description>Data map created automatically using the map settings specified during an import.</Description>
  <EntitiesPerFile>Multiple</EntitiesPerFile>
  <EntityMaps>
    <EntityMap TargetEntityName="incident" SourceEntityName="Case" Dedupe="Ignore" ProcessCode="Process">
      <AttributeMaps>
        <AttributeMap>
          <SourceAttributeName>Case Title</SourceAttributeName>
          <TargetAttributeName>title</TargetAttributeName>
          <ProcessCode>Process</ProcessCode>
        </AttributeMap>
        <AttributeMap>
          <SourceAttributeName>Customer</SourceAttributeName>
          <TargetAttributeName>customerid</TargetAttributeName>
          <ProcessCode>Process</ProcessCode>
          <LookupMaps>
            <LookupMap>
              <LookupType>System</LookupType>
              <LookupEntityName>account</LookupEntityName>
              <LookupAttributeName>name</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
            <LookupMap>
              <LookupType>System</LookupType>
              <LookupEntityName>account</LookupEntityName>
              <LookupAttributeName>accountid</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
            <LookupMap>
              <LookupType>System</LookupType>
              <LookupEntityName>contact</LookupEntityName>
              <LookupAttributeName>contactid</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
            <LookupMap>
              <LookupType>System</LookupType>
              <LookupEntityName>contact</LookupEntityName>
              <LookupAttributeName>fullname</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
          </LookupMaps>
        </AttributeMap>
      </AttributeMaps>
    </EntityMap>
    <EntityMap TargetEntityName="account" SourceEntityName="Account" Dedupe="Eliminate" ProcessCode="Process">
      <AttributeMaps>
        <AttributeMap>
          <SourceAttributeName>Account</SourceAttributeName>
          <TargetAttributeName>name</TargetAttributeName>
          <ProcessCode>Process</ProcessCode>
        </AttributeMap>
        <AttributeMap>
          <SourceAttributeName>Contact</SourceAttributeName>
          <TargetAttributeName>primarycontactid</TargetAttributeName>
          <ProcessCode>Process</ProcessCode>
          <LookupMaps>
            <LookupMap>
              <LookupType>System</LookupType>
              <LookupEntityName>contact</LookupEntityName>
              <LookupAttributeName>fullname</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
            <LookupMap>
              <LookupType>Source</LookupType>
              <LookupEntityName>Contact</LookupEntityName>
              <LookupAttributeName>Contact</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
          </LookupMaps>
        </AttributeMap>
      </AttributeMaps>
    </EntityMap>
    <EntityMap TargetEntityName="contact" SourceEntityName="Contact" Dedupe="Eliminate" ProcessCode="Process">
      <AttributeMaps>
        <AttributeMap>
          <SourceAttributeName>Contact</SourceAttributeName>
          <TargetAttributeName>lastname</TargetAttributeName>
          <ProcessCode>Process</ProcessCode>
        </AttributeMap>
        <AttributeMap>
          <SourceAttributeName>Account</SourceAttributeName>
          <TargetAttributeName>parentcustomerid</TargetAttributeName>
          <ProcessCode>Process</ProcessCode>
          <LookupMaps>
            <LookupMap>
              <LookupType>System</LookupType>
              <LookupEntityName>account</LookupEntityName>
              <LookupAttributeName>name</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
            <LookupMap>
              <LookupType>Source</LookupType>
              <LookupEntityName>Account</LookupEntityName>
              <LookupAttributeName>Account</LookupAttributeName>
              <ProcessCode>Process</ProcessCode>
            </LookupMap>
          </LookupMaps>
        </AttributeMap>
      </AttributeMaps>
    </EntityMap>
  </EntityMaps>
</Map>

*Which i will explain each node..

The most important is this XML Node:

image

This will indicate, eventhough it is in single file, you want to split them into different entities.

Now, for making it clearer, I try to hide the detail thing first and put the high level perspective here:

image

Basically, we have 4 important components

Map Source Node

-> This node is important because this will become the unique identifier for naming the Data Map

Description

-> Not important but you gonna need it to make it clearer

Entities Per File

-> Single or Multiple?

-> Very important to indicate whether you want to import to split or one entity only

Entity Maps

-> Very Important

-> You need this for mapping, the very fundamental thing

-> Can have multiple <EntityMap/> node that the number will determine how many multiple entities you want to import to

Entity Map

Now, here is your mapping for each entity:
Case

image

I have Case Title + Customer fields as Source and Target.

While for Case Title it is very straight-forward because it is a Text field, while for Customer field, little bit difficult because it is a lookup field and not only to single entity with single field as reference.
Account

image

I will have Source field: Account and Contact in my source files which i want to link them together.

I want to create new Account with Primary Contact  from my Contact field and vice versa for Contact below
Contact

image

I need to make sure that the Contact will be linked to the Account as Company.

*You need to make sure that the Source and Target are correct, but CRM would always check it once you try to import the Data Map

#3 Import the Data Map

Now just import it to the Data Map

Microsoft Dynamics CRM –> Settings –> Data Management –> Data Maps

image

And then click Import

Then the system will validate it.

#4 Back to the Source Files and Fill the Data

You can back to your file again to do re-checking before importing (even though you can delete it later)

image

So example here, I expect I will create new Case for row 5 and 6 with new Customer (Account/Contact that link each other).

I expect the system will create new Case with Title = Question about new Membership, with Customer = Aileen Gusni,

To make it happened, at first, the system need to create Aileen Gusni as Contact first, but Aileen Gusni also needs Jakarta Fluid Tech as her Company name.

So, CRM will also create Jakarta Fluid Tech as Account with Primary Contact = Aileen Gusni and Vice Versa, Jakarta Fluid Tech as Aileen Gusni’s Company name. While the newly created Case will be linked to Aileen Gusni as the customer.

And so on..Same for other Cases, Accounts, and Contacts.

#5 Import To CRM


Import to CRM as usual, but remember to Use our Data Map


image

You can see the Mapping, you would notice that the system will auto-map into 3 entities as same as you defined in the data Map, especially the <EntityMaps> node. you can make it ‘Ignore’ or just leave it and Next


image

And here is the Review Mapping Summary, you will realize that the CRM auto-split the field into 3 different actions of Entity import as pre-defined Entities in your Data Map.

image

Result

After the Import was completed, I go to the Case and I find this!

Case with Customer (Contact) Detail

image

As per our expectation.

Case Title and Customer are correct, while we know that Aileen Gusni is working for Jakarta Fluid Tech company.

Now, let’s go to the Company itself.

Company/Account Detail


image

Yes, as we can see the Primary Contact is beautifully set to the correct name.

Same as well with the other Account and Contact: Troy Co. and Adam Hings

image

Conclusion

Now, we understand that using the Data Map, you can do bulk import across multiple entities and multiple attributes, not only limited to one entity as well. Then you can also solve the big problem the ‘which one is the first’ question.

To make new data map, need to learn the XML Schema first, but never mind CRM will do checking for you.

I’d recommend to you to use the XML Editor or Visual Studio XML Editor, you can also use Notepad or Notepad ++ if you wish Smile.

In this post, I explained about how powerful data map can be your helper to do bulk import without you need to make effort in splitting them into 3 different files and import them in correct sequence, because CRM has capability to know its sequences. I believe that this is not only limited to 3 entities.

Hope this helps!

Thanks.

Tips & Tricks: How To Solve the Common Bulk Import Problem: ‘The Lookup Reference Could Not Be Resolved” in CRM Import Wizard

Have you ever thought that importing data to CRM using OB Import feature is little bit troublesome and difficult?

Issue Introduction

For example, you are trying to import Cases (Bulk) to CRM with Case Title and Customers then you found that some of your records were failed because of this common issue:

image

image

That is “The lookup reference could not be resolved”

If yes.. Then we encounter the same challenge.

Yes, that happens and happens in most times during import.

Caused by you are trying to refer the lookup field to a record that is not existing record in CRM, so the system would confused and trying to find the correct Master Data reference.

Your are expecting to make sure that if I try to do bulk import, if the lookup reference could not be found or resolved, the system would auto-detect and auto-create the reference record, for example here is to create Customer record, either Account or Contact.

While the system would reject it if you just use the one file containing direct columns.

image

*While, Row No 5 and 6 are not referring to existing Lookup.

The system would not auto-create this if you keep importing the data with that manner since it is a lookup field and mentioned ‘must already exist…’

Workarounds

You can use the SSIS or any other third party tool, but, i am in budget constraint and not going to buy new tool. What should I do?

#Create Separated Files

1. Create another file to store the Customer record, Account and Contact

image

2. Zip them together

image

3. Now import the zipped file to CRM and do mapping

image

4. Waiting…

image

5. Result

Result

Here we go..
The result..

image

As you can see that new all Cases have been imported successfully without any error.
CRM can auto-create the un-existing records if you specifically split them.

Because CRM can detect from the source, which entity record should be created at first before creating other records.

Yes..Now, all my Cases records has been inserted into CRM, plus I have managed to achieve my objection to create the new customer record.

Without this way, the system can’t automatically create the reference record even though CRM knows that those lookup reference are not existing records and need to be created first, you need to provide more data to CRM in form of new separated files.

Despite it gives you possibility to achieve that, there is still an obstacle because you don’t know about the lookup existence until you tried it? Your objective should be doing similar to ‘Upsert’ operation which is system can auto-detect the records exist or not, if not then create new one, otherwise just refer it.

How I know that the records are already exist or not? Well, you need to massage your data, such as export all the Account/Contact then using VLookup function manually in CRM to find the data, you use SQL Query or ODataQuery, or you just try and error then just export out those which failed and then extract out the columns and create them in new separated files.

Hope this helps!
Thanks.

Tuesday 14 April 2015

How to Show the Missing ‘Report Data’ in SSRS Development

A quick post, just in case you are creating SSRS or continue from anyone project and you found that you lost the ‘Report Data’ properties box, so here I am, facing the same issue.

image

Solution

A simple solution: Just press: CTRL + ALT + D

Result

SNAGHTML6507de

Hope this can save your day.
Thanks!

Monday 13 April 2015

Get Current User Setting Timezone CRM C#

Sometimes we need to get the current user timezone, so here is the code:

public int? RetrieveCurrentUsersTimeZoneSettings(IOrganizationService service)
{
     var currentUserSettings = service.RetrieveMultiple(
     new QueryExpression("usersettings")
     {
        ColumnSet = new ColumnSet("localeid", "timezonecode"),
        Criteria = new FilterExpression
        {
            Conditions =
        {
            new ConditionExpression("systemuserid", ConditionOperator.EqualUserId)
        }
        }
     }).Entities[0].ToEntity<Entity>();
     return (int?)currentUserSettings.Attributes["timezonecode"];
}


*You just need to pass the current CRM Service
Hope this helps.

Thanks.

Saturday 4 April 2015

Utilizing ‘ReplacePrivileges’ Plugin Message in CRM C#

In this post will talk about ‘ReplacePrivileges’ Message.

Introduction

This message will be triggered if you change the set of privilege collections from a security role.
In short word, when you change the ‘circle’ in the Security Role setting

image

When To Use?

Interfere this Plugin Message can be useful for some situations, example:

1. Prevent human error in security role modification for specific security role that already the best in the production.
Often, we have human error, this one cannot access, that one also cannot access, it can be caused by human error, someone accidently revoke or remove a privilege that is required to perform some action.

In addition, we cannot also remove some basic privilege that must be there to login and access CRM Data, such as System Form, User Settings, etc. This can be prevented by give validation by doing intervention of this plugin message

2. Prevent user from ‘abuse of power’ action
In some organization which is security is very important, you cannot just grant common role person a privilege to delete important records, right? For example for Salesperson, do not delete Competitor record, Customer Service cannot delete existing Case, etc.

But, we cannot just let it go and blame who if that happened? We can prevent it by add some logic in this plugin message.

3. Logging Purpose
We can actually turn on Auditing in CRM, but for advance log, you can put your logging logic into this plugin message.

Sample Code

First Sample, Prevent Any Changes for ‘Salesperson’ Role

Many people are assigned to Salesperson role, so maintaining its security is very important.

You have set correctly a privilege in the development server, you want to make sure that no one, including the new System Administrator (if you resigned) to not be able to make any changes.

So, here is the sample code:

public void Execute(IServiceProvider serviceProvider)
{
     #region must to have

     IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

     IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

     // Create service with context of current user
     IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

     //create tracing service
     ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

     #endregion

     Guid guidRoleId = new Guid();

     if (context.InputParameters.Contains("RoleId"))
     {
         guidRoleId = (Guid)context.InputParameters["RoleId"];               
     }

     //To prevent any changes for Salesperson privilege
     if(GetRoleName(service, guidRoleId).ToString().ToLower() == "Salesperson".ToLower())
     {
         throw new InvalidPluginExecutionException("Please do not modify any changes for Salesperson Role!, do not dare to do it!");
     }
}

private string GetRoleName(IOrganizationService service, Guid guidRoleId)
{
     Entity enRole = null;
     string strRoleName = string.Empty;

     enRole = service.Retrieve("role", guidRoleId, new ColumnSet("name"));

     if (enRole != null)
     {
         strRoleName = enRole.GetAttributeValue<string>("name");
     }
     return strRoleName;          
}

Result:

image

Second Sample, Prevent Grant ‘Delete’ Privilege for ‘Competitor’


We don’t want Salesperson to delete the ‘Competitor’ record and we don’t want any human error to give the privilege (prvDeleteCompetitor).

image

Here is the code:

public void Execute(IServiceProvider serviceProvider)
{
      #region must to have

      IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

     IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

      // Create service with context of current user
     IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

     //create tracing service
     ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

      #endregion

      Guid guidRoleId = new Guid();

       if (context.InputParameters.Contains("RoleId"))
       {
            guidRoleId = (Guid)context.InputParameters["RoleId"];               
       }

      //To prevent changes for Salesperson privilege
       if (GetRoleName(service, guidRoleId).ToString().ToLower() == "Salesperson".ToLower())
       {
            if (context.InputParameters.Contains("Privileges"))
            {
               RolePrivilege[] privileges = (RolePrivilege[])context.InputParameters["Privileges"];
               foreach (RolePrivilege rolePrivilege in privileges)
               {
                    //To prevent granting 'Delete' Access for 'Competitor' Entity
                    if(GetPrivilegeName(service, rolePrivilege.PrivilegeId) == "prvDeleteCompetitor")
                    {
                        throw new InvalidPluginExecutionException("Please do not give this Delete Competitor Privilege for Salesperson");
                     }                           
                }
              }
       }                   
}

private string GetRoleName(IOrganizationService service, Guid guidRoleId)
{
     Entity enRole = null;
     string strRoleName = string.Empty;

     enRole = service.Retrieve("role", guidRoleId, new ColumnSet("name"));

     if (enRole != null)
     {
          strRoleName = enRole.GetAttributeValue<string>("name");
     }

          return strRoleName;          
}

private string GetPrivilegeName(IOrganizationService service, Guid guidPrivilegeId)
{
     Entity enPrivilege= null;
     string strPrivilegeName = string.Empty;

     enPrivilege = service.Retrieve("privilege", guidPrivilegeId, new ColumnSet("name"));

     if (enPrivilege != null)
     {
         strPrivilegeName = enPrivilege.GetAttributeValue<string>("name");
     }

     return strPrivilegeName;
}

Result:

image

image

Checking Privilege Depth

You can use rolePrivilege.Depth also to check, whether this is Basic, Deep, Local or Global Access.

https://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.privilegedepth.aspx

How to Register The Plugin

Message: ReplacePrivileges

Primary Entity: role

Register as Pre-Operation or Post-Operation so far I don’t see any difference for this message, but better you register Pre-Operation stage for validation.

Hope this helps!

Thanks.

Friday 3 April 2015

Alter Lookup Field/Column Displayed Value In the CRM View Using C#

When the users go to CRM and access the Entity View, the objective is they want to see the list of complete data, that they don’t want to click and enter each record, one by one.

Scenario

Often we can see a field showing same value, but in fact it should refer to different record.
Here is for example:

image

As we can see here, there are many Cases referring to same Customer Name (for example: Adventure Works), but actually, are they? Are they the same ‘Adventure Works’ or not?

Well, if we click one by one, we will know that they are different, because in fact we have  a lot of Adventure Works around the world (can be in Jakarta, Sydney, Singapore, Canada, etc.) or we can just add new columns to display, but it means consume another column space, and imagine every time you need to add the columns to the view, including your personal view.

Now, let’s tweak it little bit, I want to see the Case from which Customer, really, I want to know which the customer, exactly? Is that from Jakarta, Sydney, or any other branch.

Expected Result

I want to get like this:

Case 1        Adventure Works [Jakarta, Indonesia]
Case 2        Adventure Works [Sydney, Australia]

Not only showing ‘Adventure Works’

I want to concatenate the multiple fields into single lookup field column.

The Code

Here is the Sample C# Code to manipulate the lookup displayed value.

public void Execute(IServiceProvider serviceProvider)
 {
     #region must to have

     IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

     IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

     // Create service with context of current user
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

     //create tracing service
     ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

     #endregion

     if (context.OutputParameters.Contains("BusinessEntityCollection"))
     {
          var retrievedResult = (EntityCollection)context.OutputParameters["BusinessEntityCollection"];
          foreach (Entity entity in retrievedResult.Entities)
          {
              //retrieve the CustomerId Entity Reference
              if (entity.Contains("customerid"))
              {
                  EntityReference erCustomerId = (entity.Attributes["customerid"] as EntityReference);

                  if (erCustomerId != null)
                  {
                      //retrieve the customerid detail
                      Entity enCustomer = new Entity();
                      enCustomer = service.Retrieve(erCustomerId.LogicalName, erCustomerId.Id, new ColumnSet("address1_city", "address1_country"));

                      //retrieve the City and Country detail
                      string strCity = enCustomer.Contains("address1_city") ? enCustomer["address1_city"].ToString() : string.Empty;
                      string strCountry = enCustomer.Contains("address1_country") ? enCustomer["address1_country"].ToString() : string.Empty;

                      //alter the displayed value for column name
                      erCustomerId.Name = string.Format("{0} [{1}, {2}]", erCustomerId.Name, strCity, strCountry);
                  }
              }
          }
      }
}

How to Register Your Plugin

Please register your Plugin with the following config:

image

Message: RetrieveMultiple

Primary Entity: incident

Event of Execution: Post-Operation

And it is Synchronous Plugin.

Result


Now, see the result here:

image

*As we can see, you can see the additional information that is in separated fields to be displayed in single column.

This is also can be workaround for the CRM Limitation to only get the column from up to one level related entity.

So, let’s say you have Customer as the Lookup field, then you can only get the Columns from the Account/Contact, you cannot get the Column from the Lookup detail of the Account, for example: Originating Lead's Columns, Account Owner’s columns, etc.

It also does not consume to much space and you can put another detail, concatenate multiple columns into single column display.

Hope this helps!

Thanks.

Enable Modifying Unit Group in Existing Product Using Business Rules

As we know that we cannot modify Unit Group field in the CRM Existing Product record:

image

What if we want to Update the Unit Group?

Well, you can use Data Import feature.

What if we only want to update one record?

We can actually utilize the Business Rules as a trick

1. Create a Business Rule for Product

image

You can do any If, can be Product Name, Product ID or any dedicated field just to trigger the ‘Unlock’

And then for the Action, just make the Unit Group in ‘Unlock’ position.

2. Activate it

3. To Make it works, you need to trigger it (since the onLoad will be overridden by CRM Validation, it will lock again the Unit Group, so you need to change the field value to trigger it)

I just type a (anything actually) in the Description field

image

4. You can change the Unit Group

image

Note

1. This is a trick to update Unit Group just in case you want update in single record, it is useful to avoid hassle in importing effort just for single record
2. Remember to always memorize the field you changed to trigger and change the Default Unit accordingly by the new Unit Group Smile
3. Since CRM blocks it, Do at your own risk. Smile

Thank you!

Skyvia: Backup Your Data via The Sky

In my previous post, I was talking about Skyvia as my introduction part. As we know Skyvia is a product to help the data integration and backup in the cloud, now let’s talk first about the backup.

Since my blog is particularly purposed to Dynamics CRM-all about, so here I want to research its capability in term of CRM Backup and write every single step here, and yes, I try it on CRM Online! (As we know it is not possible for us to do backup CRM Online by ourselves without the favor from Microsoft Team).

Steps

1. Sign up and Login

Now, I have been logged in here:

image

2. Create a New Connection

image

image

Select the Dynamics CRM (for those who are not CRM Users, don’t worry, there are plenty other options)

3. Fill up The Connection Configuration Form and Test Connection, then Save it.

image

4. Go to Backup

image

5. Create New Backup Package, Select Connection

image

6. Select your Object to Backup

Well, to backup, you need to choose what Object you want to Backup, so it is Object-Based Backup.
This is very useful if you want to backup partial data that is very important.

image

7. Now, I want to Backup Account and Contact

image

8.Not only that, when you click the ‘edit’ you can perform more.

image

You can filter to not backup all Fields and can Filter by Condition.

And you can perform grouping: And, Or, and Xor (maybe more powerful than the Advance Find Smile)

image

But, now I don’t want to play around with this, I just want to backup all.

9. Setup Schedule

As usual Database Backup Task, we can set a schedule or just make it as one time only.

image

image

I make it as One-Time only in my research.

image

10. Now Back to the Top and Save it.

image

11. Backup is in Progress…

You can see the status here and you can also Force Backup Now if you already schedule it later but you want to have it immediately

image

Scrolling down, later you can se the Records and also the History of the Backup

image

*History in Calendar View

image

12. You can Create Multiple Backup Packages

image

Just wait, it’s about 30 minutes waiting

Now I can get the Report

image

That’s all the steps to backup your database.

Backup Method

Where is it stored?

According to the Engineer, Jacob Martin
Backed up data is stored in a secure Azure Geo-redundant storage (GRS), and these data are always available for viewing and restoring.

Can we Download the Data?

Skyvia allows downloading backed up data as CSV files. It does not allow downloading them as a database. However, you can view all the backed up data in the browser, filter and search them, and restore them in a couple of clicks.

What’s Next

The question now is what’s next? Is that just a backup? No, actually you can perform Update, Insert, and Delete from the selected Backup

Skyvia Backup Features (Update, Insert, Delete)

As mentioned before, this is not only just backup and that’s all. No. It is like a snapshot, imagine you are running Virtual Machine, then something happened, it gets crashed, you can just recover it all.
Now, imagine in the CRM if you accidently delete or update a record, can you undo it?
You can recover it, but you need the Audit history and recover it programmatically, which is for end users it is not recommended.

Skyvia as The Snapshot-er

Recover the Deleted Records

Back to CRM and I delete one of the Account record

image

As we can see, there is a confirmation box and also warning box as caveats to us to re-think again before we delete any record, because WE CAN”T UNDO THIS ACTION.

And Again…Another box comes up.

image

Now back to the Skyvia backup and then select the backup that we have performed before.

Search the data

image

Now, back to the left side, scroll left horizontally and then tick the selected record

image

It will open the ‘Restore’ account

Now, just click the ‘Insert Records’

Restore is in progress….

image

image

Restored Result

image

You can get the report, 1 record has been Restored, now let’s back to CRM.

And we search the record..

image

The record is successfully restored! Saved the day.

Undo the Changes

We learned how this Skyvia helps us to re-insert the deleted record.

Now, back to CRM and the users suddenly change the City and State to incorrect value, Sydney and DKI Jakarta

image

Now, I want to undo the changes

I go back to Skyvia and then perform the Update

image

Undo Result

image

Then back to CRM

image

The Address is back to its original value!

Delete Record

Now we want to delete the record in CRM easily, you can just delete from its snapshot.

I want to delete Brian Burke

image

We know we can delete it from CRM UI, but let’s try to delete from Skyvia.

image

Now no more Brian Burke in CRM

image

You can later recover it back.

History of Actions

image

image

Overall

Strengths:

- This is very useful for restoring data, undo changes, and delete just from the snapshot as long as you have the backup (of course)
- All the actions are performed in very simple steps with fancy UI
- Definitely No need to have programmatically knowledge
- No effort to create Integration environment, because all-in-one in Cloud
- Every single actions are stored and you can see in the History
As usual, there is no perfect product, so it still has Limitations

Limitations:
- Simple logic only, you can just search the record by keyword, so far no complex logic
- Restoring is object by object, can be positive for particular data (no hassle), but negative for big data
- The restored records concept is using Insert, so it will use the New GUID, so that you will lose the first Guid, lose the relationship as well
- Same concept with previous one, the ‘created on’ field will have today value, not the original ‘created on’ field

Thanks and stay tune in the next post!