Skip to content

Commit

Permalink
added ability to create many-to-many relationship associations in the…
Browse files Browse the repository at this point in the history
… target system
  • Loading branch information
lucasalexander committed Nov 28, 2017
1 parent f250262 commit 1390b07
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 132 deletions.
4 changes: 4 additions & 0 deletions AlexanderDevelopment.ConfigDataMover.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ static void ParseConfig(string filepath)
if (xn.Attributes["createOnly"] != null)
step.CreateOnly = Convert.ToBoolean(xn.Attributes["createOnly"].Value);

step.ManyMany = false;
if (xn.Attributes["manyMany"] != null)
step.ManyMany = Convert.ToBoolean(xn.Attributes["manyMany"].Value);

_jobSteps.Add(step);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("2.2.*")]
[assembly: AssemblyVersion("2.3.*")]
291 changes: 182 additions & 109 deletions AlexanderDevelopment.ConfigDataMover.Lib/Importer.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions AlexanderDevelopment.ConfigDataMover.Lib/JobStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ public class JobStep
public string StepFetch { get; set; }
public bool UpdateOnly { get; set; }
public bool CreateOnly { get; set; }
public bool ManyMany { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("2.2.*")]
[assembly: AssemblyVersion("2.3.*")]
1 change: 1 addition & 0 deletions AlexanderDevelopment.ConfigDataMover.Wpf/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<ComboBoxItem Name="stepTypeBoth" Content="Create and update" IsSelected="True"/>
<ComboBoxItem Name="stepTypeCreate" Content="Create only"/>
<ComboBoxItem Name="stepTypeUpdate" Content="Update only"/>
<ComboBoxItem Name="stepTypeManyMany" Content="Many to many"/>
</ComboBox>
</StackPanel>
<TextBox x:Name="stepFetchTextBox" Grid.Row="1"
Expand Down
59 changes: 39 additions & 20 deletions AlexanderDevelopment.ConfigDataMover.Wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ protected void openJobButton_Click(object sender, EventArgs args)
if (xn.Attributes["createOnly"] != null)
step.CreateOnly = Convert.ToBoolean(xn.Attributes["createOnly"].Value);

step.ManyMany = false;
if (xn.Attributes["manyMany"] != null)
step.ManyMany = Convert.ToBoolean(xn.Attributes["manyMany"].Value);

stepListBox.Items.Add(step);
}

Expand Down Expand Up @@ -167,28 +171,31 @@ private void saveJobButton_Click(object sender, EventArgs e)
JobStep step = (JobStep)item;
XmlElement elStep = doc.CreateElement("Step");
elStep.AppendChild(doc.CreateElement("Name")).InnerText = step.StepName;
switch ((string)stepTypeComboBox.SelectedValue)

//default createonly, updateonly and manymany attributes to false
elStep.SetAttribute("updateOnly", false.ToString());
elStep.SetAttribute("createOnly", false.ToString());
elStep.SetAttribute("manyMany", false.ToString());

//check whether to set any createonly, updateonly and manymany attributes to true
if (step.CreateOnly)
{
case "Create only":
elStep.SetAttribute("updateOnly", false.ToString());
elStep.SetAttribute("createOnly", true.ToString());
//step.UpdateOnly = false;
//step.CreateOnly = true;
break;
case "Update only":
elStep.SetAttribute("updateOnly", true.ToString());
elStep.SetAttribute("createOnly", false.ToString());
//step.UpdateOnly = true;
//step.CreateOnly = false;
break;
default:
elStep.SetAttribute("updateOnly", false.ToString());
elStep.SetAttribute("createOnly", false.ToString());
//step.UpdateOnly = false;
//step.CreateOnly = false;
break;
elStep.SetAttribute("updateOnly", false.ToString());
elStep.SetAttribute("createOnly", true.ToString());
elStep.SetAttribute("manyMany", false.ToString());
}
if (step.UpdateOnly)
{
elStep.SetAttribute("updateOnly", true.ToString());
elStep.SetAttribute("createOnly", false.ToString());
elStep.SetAttribute("manyMany", false.ToString());
}
if (step.ManyMany)
{
elStep.SetAttribute("updateOnly", false.ToString());
elStep.SetAttribute("createOnly", false.ToString());
elStep.SetAttribute("manyMany", true.ToString());
}

elStep.AppendChild(doc.CreateElement("Fetch")).InnerText = step.StepFetch;
elSteps.AppendChild(elStep);
}
Expand Down Expand Up @@ -437,6 +444,10 @@ private void stepListBox_SelectedIndexChanged(object sender, EventArgs e)
{
stepTypeComboBox.SelectedValue = "Create only";
}
if(step.ManyMany)
{
stepTypeComboBox.SelectedValue = "Many to many";
}
//updateOnlyCheckBox.IsChecked = step.UpdateOnly;
}
else
Expand Down Expand Up @@ -550,14 +561,22 @@ private void updateStepButton_Click(object sender, RoutedEventArgs e)
case "Create only":
step.UpdateOnly = false;
step.CreateOnly = true;
step.ManyMany = false;
break;
case "Update only":
step.UpdateOnly = true;
step.CreateOnly = false;
step.ManyMany = false;
break;
case "Many to many":
step.UpdateOnly = false;
step.CreateOnly = false;
step.ManyMany = true;
break;
default:
step.UpdateOnly = false;
step.CreateOnly = false;
step.ManyMany = false;
break;
}
stepListBox.Items[stepListBox.SelectedIndex] = stepListBox.SelectedItem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("2.2.*")]
[assembly: AssemblyVersion("2.3.*")]
32 changes: 32 additions & 0 deletions README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# AlexanderDevelopment.ConfigDataMover
This is a tool used for making sure that configuration data like teams and queues have the same record GUIDs in all of a Dynamics CRM project's different environments for development, testing and production. For more information, please see the related posts on my blog: [http://alexanderdevelopment.net/tag/configuration-data-mover/](http://alexanderdevelopment.net/tag/configuration-data-mover/)

Here's an explanation of the various settings and parameters that can be specified in the GUI:

1. Source (one of the following):
1. CRM connection string for source organization
1. Path to source data file - value will start with "file="
1. Full path to source data JSON file in the form of "C:\datadirectory\datafile.json."
1. Relative path to source data JSON file in the form of "..\datafile.json." (Path is relative to working directory.)
1. Raw JSON string with contents of an export file - value will start with "rawjson="
1. Target (one of the following)
1. CRM connection string for source organization
1. Path to target data file - value will start with "file="
1. Full path to target data JSON file in the form of "C:\datadirectory\datafile.json."
1. Relative path to target data JSON file in the form of "..\datafile.json." (Path is relative to working directory.)
1. Save connection details? - If checked, connection details should be saved in configuration file. Note, connection details are unencrypted.
1. Map root business unit GUID? - If checked, the job will automatically change any GUID references from the source organization root business unit to the target organization root business unit. This will also apply to any GUID references for the root business unit's default team.
1. Map base currency GUID? - If checked, the job will automatically change any GUID references from the source organization base currency to the target organization base currency.
1. Job steps - A list of steps for each distinct entity transfer operation.
1. Step name - Sets the name of the selected job step. The step name is used in logging outputs.
1. Step FetchXML query - The FetchXML query that determines which records and specific attributes will be transfered.
1. Step type - Sets a step's behavior to (a) only create new records, (b) only update existing records, (c) create new records and update existing records or (d) create a many-to-many association
1. GUID mappings - List of GUIDs in the source organization that will be replaced with GUIDs in the target organization.

### Caveats/considerations:

1. The GUI client does a basic validation to check if the supplied query is valid XML when you enter it. When you save a job, each step's FetchXML is valdiated against the CRM 2016 FetchXML XSD, and any validation issues will prevent saving. Note, this only validates the FetchXML is structurally valid, but it does not check for correctness as far as entity names, attribute names, relationships, etc. All FetchXML queries are also checked by the importer at runtime, so any validation problems will prevent job execution.
1. Following up on the previous point, if you include an attribute in the query that you aren't able to update in the target, the tool won't know any better, and you will get an error when the job is executed.
1. Because only the attributes included in the FetchXML query are used for updating/creating a record in the target system, you can sequence record creation and update steps by using different FetchXML queries in different steps.
1. The FetchXML query for a many-to-many job step should be a query against the relationship entity (relationship entity name on the many-to-many relationship form) that includes the GUID fields for each entity. The relationship entities cannot be queried in the advanced find builder, so you must write the FetchXML manually or use a separate query builder.
1. A many-to-many job step will create many-to-many record associations, but it will not delete any existing N:N associations in the target system that have been removed in the source.

0 comments on commit 1390b07

Please sign in to comment.