Skip to content

Commit

Permalink
Added support for only creating foreign keys for the most common colu…
Browse files Browse the repository at this point in the history
…mns since Salesforce a non-nillable doesn't guarantee non-null data
  • Loading branch information
Jeff Martin committed Jun 22, 2018
1 parent a32ebfe commit bd7fa48
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 13 deletions.
3 changes: 3 additions & 0 deletions SalesforceSQLSchemaGenerator/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
<setting name="SalesforceRememberSelectedObjects" serializeAs="String">
<value>True</value>
</setting>
<setting name="SqlGenerateForeignKeysSelectedObjectsOnly" serializeAs="String">
<value>True</value>
</setting>
</SalesforceSQLSchemaGenerator.Properties.Settings>
<SalesforceSQLSchemaGenerator.SalesforceSQLSchemaSync>
<setting name="SalesforceURL" serializeAs="String">
Expand Down
11 changes: 9 additions & 2 deletions SalesforceSQLSchemaGenerator/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d"
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
Title="Salesforce SQL Schema Generator" Height="768" Width="1024"
Title="Salesforce SQL Schema Generator" Height="768" Width="1274"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<DockPanel>
<StatusBar DockPanel.Dock="Bottom">
Expand Down Expand Up @@ -99,7 +99,14 @@
</Label>
<TextBox Grid.Row="2" Grid.Column="1" Margin="{Binding DefaultMargin}" Text="{Binding SqlVarcharMaxMinimumThreshold}" TextChanged="SaveSqlInfo" />
<CheckBox Grid.Row="3" Grid.Column="1" Margin="{Binding DefaultMargin}" IsChecked="{Binding SqlTextUnicode}" Content="Define text data as UNICODE (use NVARCHAR)" Unchecked="SaveSqlInfo" Checked="SaveSqlInfo" />
<CheckBox Grid.Row="4" Grid.Column="1" Margin="{Binding DefaultMargin}" IsChecked="{Binding SqlGenerateForeignKeys}" Content="Generate foreign keys" Unchecked="SaveSqlInfo" Checked="SaveSqlInfo" />
<Grid Grid.Row="4" Grid.Column="1" Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Padding="0,0,19,0" Margin="{Binding DefaultMargin}" IsChecked="{Binding SqlGenerateForeignKeys}" Content="Generate foreign keys" Unchecked="SaveSqlInfo" Checked="SaveSqlInfo" />
<CheckBox Grid.Row="0" Grid.Column="1" Margin="{Binding DefaultMargin}" IsChecked="{Binding SqlGenerateForeignKeysSelectedObjectsOnly}" Content="Foreign keys only for selected objects" Unchecked="SaveSqlInfo" Checked="SaveSqlInfo" IsEnabled="{Binding SqlGenerateForeignKeys}" />
</Grid>
<Button Grid.Row="5" Grid.Column="1" Margin="{Binding DefaultMargin}" Content="Generate Script for Selected Objects" Width="250" HorizontalAlignment="Left" Click="GenerateSqlScript_Click" Visibility="{Binding GenerateScriptVisibility}"/>
<Grid Grid.Row="6" Grid.Column="1" Visibility="{Binding SaveScriptVisibility}" Margin="0,19,0,0">
<Grid.ColumnDefinitions>
Expand Down
50 changes: 39 additions & 11 deletions SalesforceSQLSchemaGenerator/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ public string StatusText {
public bool SqlTextUnicode { get; set; }
public int? SqlVarcharMaxMinimumThreshold { get; set; }
private string SqlSaveDirectory { get; set; }
public bool SqlGenerateForeignKeys { get; set; }
private bool sqlGenerateForeignKeys = true;
public bool SqlGenerateForeignKeys {
get {
return sqlGenerateForeignKeys;
}
set {
sqlGenerateForeignKeys = value;
OnPropertyChanged("SqlGenerateForeignKeys");
}
}
public bool SqlGenerateForeignKeysSelectedObjectsOnly { get; set; }

public ObservableCheckedListItemCollection SalesforceObjects { get; set; }

Expand All @@ -80,6 +90,18 @@ public Visibility SaveScriptVisibility {
}
}

private string[] AllowedNullableFieldNames = new string[] {
"Id",
"CreatedById",
"CreatedDate",
"LastModifiedById",
"LastModifiedDate",
"SystemModstamp",
"IsDeleted",
"Name",
"OwnerId"
};

public Thickness DefaultMargin { get; set; }
private Dictionary<string, string> GeneratedSqlScript = new Dictionary<string, string>();

Expand All @@ -103,7 +125,8 @@ public MainWindow() {
SalesforceToken = SettingsManager.GetSecureString("SalesforceToken");
}
SalesforceRememberSelectedObjects = SettingsManager.GetValue<bool>("SalesforceRememberSelectedObjects");
if(SalesforceRememberSelectedObjects && SettingsManager.GetValue<StringCollection>("SalesforceSelectedObjects") != null) {
SqlGenerateForeignKeysSelectedObjectsOnly = SettingsManager.GetValue<bool>("SqlGenerateForeignKeysSelectedObjectsOnly");
if (SalesforceRememberSelectedObjects && SettingsManager.GetValue<StringCollection>("SalesforceSelectedObjects") != null) {
SalesforceSelectedObjects = SettingsManager.GetValue<StringCollection>("SalesforceSelectedObjects");
}
SqlSchemaName = SettingsManager.GetString("SqlSchemaName");
Expand Down Expand Up @@ -131,7 +154,7 @@ public MainWindow() {
}
#endregion

#region INotifyPropertyChanged implementation
#region INotifyPropertyChanged - PropertyChanged; OnPropertyChanged();
// Basically, the UI thread subscribes to this event and update the binding if the received Property Name correspond to the Binding Path element
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
Expand Down Expand Up @@ -250,6 +273,7 @@ private void SaveSqlInfo() {
SettingsManager.SetValue("SqlTextUnicode", SqlTextUnicode);
SettingsManager.SetNullableValue("SqlVarcharMaxMinimumThreshold", SqlVarcharMaxMinimumThreshold);
SettingsManager.SetValue("SqlGenerateForeignKeys", SqlGenerateForeignKeys);
SettingsManager.SetValue("SqlGenerateForeignKeysSelectedObjectsOnly", SqlGenerateForeignKeysSelectedObjectsOnly);
}
}
#endregion
Expand Down Expand Up @@ -363,9 +387,9 @@ public Dictionary<string,string> GenerateSqlScript() {
if (SqlVarcharMaxMinimumThreshold != null && f.length >= SqlVarcharMaxMinimumThreshold.Value) {
sb.Append(string.Format("[{0}] {1}(MAX)", f.name, stringDataType));
}
else if(f.length == 0) {
if(SqlVarcharMaxMinimumThreshold.Value > 2000) {
sb.Append(string.Format("[{0}] {1}({2})", f.name, stringDataType, "2000")); //assume 2000 length based on some testing (data may come through as XML)
else if (f.length == 0) {
if (SqlVarcharMaxMinimumThreshold.Value > 2000) {
sb.Append(string.Format("[{0}] {1}({2})", f.name, stringDataType, "2000")); //assume 2000 length based on some testing (data may come through as XML)
}
else {
sb.Append(string.Format("[{0}] {1}(MAX)", f.name, stringDataType));
Expand Down Expand Up @@ -416,23 +440,27 @@ public Dictionary<string,string> GenerateSqlScript() {
sb.Append(string.Format("[{0}] {1}", f.name, f.type));
break;
}
if ((f.referenceTo != null && f.referenceTo.Length ==1) || string.Equals(f.name, "id", StringComparison.InvariantCultureIgnoreCase)) {
if ((f.referenceTo != null && f.referenceTo.Length == 1) || string.Equals(f.name, "id", StringComparison.InvariantCultureIgnoreCase)) {
sb.Append(" COLLATE SQL_Latin1_General_CP1_CS_AS");
if (f.referenceTo != null && f.referenceTo.Length == 1) {
foreignKeys.Add(new ForeignKeyEntry(t.name, f.name, f.referenceTo[0], "Id")); //hardcode foreign key to id of ref table
}
}
if (!f.nillable) {
if (!f.nillable && AllowedNullableFieldNames.Contains(f.name, StringComparer.InvariantCultureIgnoreCase)) {
sb.Append(" NOT NULL");
}
sb.AppendLine();
}
if(primaryKeys.Count > 0) {
if (primaryKeys.Count > 0) {
sb.AppendLine(string.Format(" ,CONSTRAINT [PK_{0}] PRIMARY KEY CLUSTERED ([{1}] ASC)", t.name, string.Join("], [", primaryKeys)));
//sb.AppendLine(string.Format(" ,PRIMARY KEY ([{0}])", string.Join("], [", primaryKeys)));
}
foreach(ForeignKeyEntry fk in foreignKeys) {
sb.AppendLine(string.Format(" ,CONSTRAINT [FK_{0}_{1}_{2}] FOREIGN KEY ([{1}]) REFERENCES {4}[{2}]([{3}])", fk.FromTable, fk.FromField, fk.ToTable, fk.ToField, schema));
if (SqlGenerateForeignKeys) {
foreach (ForeignKeyEntry fk in foreignKeys) {
if (!SqlGenerateForeignKeysSelectedObjectsOnly || tableNames.Contains(fk.ToTable, StringComparer.InvariantCultureIgnoreCase)) {
sb.AppendLine(string.Format(" ,CONSTRAINT [FK_{0}_{1}_{2}] FOREIGN KEY ([{1}]) REFERENCES {4}[{2}]([{3}])", fk.FromTable, fk.FromField, fk.ToTable, fk.ToField, schema));
}
}
}
sb.Append(");");

Expand Down
12 changes: 12 additions & 0 deletions SalesforceSQLSchemaGenerator/Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions SalesforceSQLSchemaGenerator/Properties/Settings.settings
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,8 @@
<Setting Name="SalesforceSelectedObjects" Type="System.Collections.Specialized.StringCollection" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="SqlGenerateForeignKeysSelectedObjectsOnly" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

0 comments on commit bd7fa48

Please sign in to comment.