Skip to content

Commit a2720d5

Browse files
authored
Initial seed data UI (#101)
1 parent 29aeff8 commit a2720d5

12 files changed

Lines changed: 262 additions & 18 deletions

File tree

‎src/DacFXTool/Program.cs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public static async System.Threading.Tasks.Task<int> Main(string[] args)
4444
};
4545

4646
var provider = new ServiceCollection().AddEfpt(reverseEngineerCommandOptions, new List<string>(), new List<string>(), new List<string>()).BuildServiceProvider();
47-
var procedureModelFactory = provider.GetRequiredService<IProcedureModelFactory>();
48-
var functionModelFactory = provider.GetRequiredService<IFunctionModelFactory>();
47+
var procedureModelFactory = provider.GetService<IProcedureModelFactory>();
48+
var functionModelFactory = provider.GetService<IFunctionModelFactory>();
4949
var databaseModelFactory = provider.GetRequiredService<IDatabaseModelFactory>();
5050
var builder = new TableListBuilder(reverseEngineerCommandOptions, procedureModelFactory, functionModelFactory, databaseModelFactory, schemas ?? []);
5151

@@ -215,10 +215,10 @@ public static async System.Threading.Tasks.Task<int> Main(string[] args)
215215
if (args.Length == 5
216216
&& (args[0] == "merge"))
217217
{
218-
MergeGenerator.Generate(args[1], args[2], args[3], args[4]);
218+
var result = MergeGenerator.Generate(args[1], args[2], args[3], args[4]);
219219

220220
await Console.Out.WriteLineAsync("Result:");
221-
await Console.Out.WriteLineAsync("OK");
221+
await Console.Out.WriteLineAsync(result);
222222

223223
return 0;
224224
}

‎src/DacFXToolLib/MergeGenerator.cs‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace DacFXToolLib
66
{
77
public static class MergeGenerator
88
{
9-
public static void Generate(string projectPath, string connectionString, string tableName, string schema)
9+
public static string Generate(string projectPath, string connectionString, string tableName, string schema)
1010
{
1111
var script = ReadScript();
1212

@@ -28,10 +28,10 @@ public static void Generate(string projectPath, string connectionString, string
2828

2929
connection.Close();
3030

31-
WriteResult(projectPath, tableName, result);
31+
return WriteResult(projectPath, tableName, result);
3232
}
3333

34-
private static void WriteResult(string projectPath, string tableName, object result)
34+
private static string WriteResult(string projectPath, string tableName, object result)
3535
{
3636
var projectDirectory = Path.GetDirectoryName(projectPath);
3737

@@ -48,6 +48,8 @@ private static void WriteResult(string projectPath, string tableName, object res
4848
}
4949

5050
File.WriteAllText(outputPath, result.ToString(), Encoding.UTF8);
51+
52+
return outputPath;
5153
}
5254

5355
private static string ReadScript()

‎src/DacFXToolLib/ServiceProviderBuilder.cs‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.EntityFrameworkCore.Infrastructure;
77
using Microsoft.EntityFrameworkCore.Scaffolding;
88
using Microsoft.EntityFrameworkCore.SqlServer.Design.Internal;
9+
using Microsoft.EntityFrameworkCore.SqlServer.Scaffolding.Internal;
910
using Microsoft.EntityFrameworkCore.Storage;
1011
using Microsoft.Extensions.DependencyInjection;
1112

@@ -38,7 +39,12 @@ public static IServiceCollection AddEfpt(this IServiceCollection serviceCollecti
3839
switch (options.DatabaseType)
3940
{
4041
case DatabaseType.SQLServerDacpac:
41-
AddSqlServerProviderServices(serviceCollection, options); break;
42+
AddSqlServerProviderServices(serviceCollection, options);
43+
break;
44+
45+
case DatabaseType.SQLServer:
46+
AddSqlServerProviderServices(serviceCollection, options);
47+
break;
4248

4349
default:
4450
throw new ArgumentOutOfRangeException(nameof(options), $"unsupported database type: {options.DatabaseType}");
@@ -55,7 +61,6 @@ private static void AddSqlServerProviderServices(IServiceCollection serviceColle
5561
#if CORE100
5662
serviceCollection.AddSingleton(new SqlServerSingletonOptions());
5763
#endif
58-
5964
if (options.DatabaseType == DatabaseType.SQLServerDacpac)
6065
{
6166
var excludedIndexes = options.Tables?.Select(t => new { t.Name, t.ExcludedIndexes });
@@ -79,6 +84,12 @@ private static void AddSqlServerProviderServices(IServiceCollection serviceColle
7984
MergeDacpacs = options.MergeDacpacs,
8085
});
8186
}
87+
88+
if (options.DatabaseType == DatabaseType.SQLServer)
89+
{
90+
serviceCollection.AddSingleton(options);
91+
serviceCollection.AddSingleton<IDatabaseModelFactory, SqlServerDatabaseModelFactory>();
92+
}
8293
}
8394
}
8495
}

‎src/DacFXToolLib/TableListBuilder.cs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using DacFXToolLib.Common;
1+
using DacFXToolLib.Common;
22
using Microsoft.EntityFrameworkCore.Scaffolding;
33
using Microsoft.EntityFrameworkCore.Scaffolding.Metadata;
44
using RevEng.Core.Abstractions;
@@ -8,8 +8,8 @@ namespace DacFXToolLib
88
{
99
public class TableListBuilder
1010
{
11-
private readonly IProcedureModelFactory procedureModelFactory;
12-
private readonly IFunctionModelFactory functionModelFactory;
11+
private readonly IProcedureModelFactory? procedureModelFactory;
12+
private readonly IFunctionModelFactory? functionModelFactory;
1313
private readonly IDatabaseModelFactory databaseModelFactory;
1414

1515
private readonly SchemaInfo[] schemas;
@@ -19,8 +19,8 @@ public class TableListBuilder
1919

2020
public TableListBuilder(
2121
ReverseEngineerCommandOptions options,
22-
IProcedureModelFactory procedureModelFactory,
23-
IFunctionModelFactory functionModelFactory,
22+
IProcedureModelFactory? procedureModelFactory,
23+
IFunctionModelFactory? functionModelFactory,
2424
IDatabaseModelFactory databaseModelFactory,
2525
SchemaInfo[] schemas)
2626
{

‎src/Lib/dacfxtool.exe.zip‎

14.1 KB
Binary file not shown.

‎src/Vsix/Commands/SeedCommand.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)
1919

2020
if (project != null)
2121
{
22-
await VS.MessageBox.ShowConfirmAsync("Seed functionality is not yet implemented.");
22+
var handler = new SeedHandler();
23+
await handler.GenerateSeedScriptsAsync(project);
2324
}
2425
}
2526
}

‎src/Vsix/Dialogs/PickServerDatabaseDialog.xaml.cs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ public PickServerDatabaseDialog(
5858
return;
5959
}
6060

61+
if (allowedVersions.Count == 1
62+
&& allowedVersions[0].Value == "Seed")
63+
{
64+
grdRow1.Height = new GridLength(0);
65+
grdRow2.Height = new GridLength(0);
66+
grdRow3.Height = new GridLength(0);
67+
return;
68+
}
69+
6170
foreach (var item in allowedVersions)
6271
{
6372
viewModel.CodeGenerationModeList.Add(item);

‎src/Vsix/Handlers/ImportHandler.cs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
using DacFXToolLib.Common;
2-
using DacFXToolLib.Dab;
3-
using Microsoft.VisualStudio.Shell.Interop;
41
using System.Collections.Generic;
52
using System.IO;
63
using System.Linq;
74
using System.Text;
85
using System.Text.Json;
96
using System.Threading.Tasks;
7+
using DacFXToolLib.Common;
8+
using DacFXToolLib.Dab;
9+
using Microsoft.VisualStudio.Shell.Interop;
1010

1111
namespace SqlProjectsPowerTools
1212
{

‎src/Vsix/Handlers/ProcessLauncher.cs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ public async Task<string> GetDabConfigPathAsync(string optionsPath, string conne
126126
return filePath;
127127
}
128128

129+
// merge "projectpath" "connectionString" "tableName" "schema"
130+
public async Task<string> CreateMergeScriptAsync(string projectPath, string connectionString, string tablename, string schema)
131+
{
132+
var arguments = "merge " + " \"" + projectPath.Replace("\"", "\\\"") + "\" " + " \"" + connectionString.Replace("\"", "\\\"") + "\" \"" + tablename.Replace("\"", "\\\"") + "\" \"" + schema.Replace("\"", "\\\"") + "\"";
133+
134+
var result = await GetDiagramInternalAsync(arguments);
135+
136+
return result;
137+
}
138+
129139
private static async Task<string> RunProcessAsync(ProcessStartInfo startInfo)
130140
{
131141
return await ExternalProcessLauncher.RunProcessAsync(startInfo);

‎src/Vsix/Handlers/SeedHandler.cs‎

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using DacFXToolLib.Common;
6+
using DacFXToolLib.Dab;
7+
8+
namespace SqlProjectsPowerTools
9+
{
10+
internal class SeedHandler
11+
{
12+
public async Task GenerateSeedScriptsAsync(Project project)
13+
{
14+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
15+
16+
try
17+
{
18+
if (await VSHelper.IsDebugModeAsync())
19+
{
20+
VSHelper.ShowError("Cannot generate code while debugging");
21+
return;
22+
}
23+
24+
var options = new DataApiBuilderOptions();
25+
26+
var info = await ChooseDataBaseConnectionAsync(options);
27+
28+
if (info.DatabaseModel == null)
29+
{
30+
return;
31+
}
32+
33+
var dbInfo = await GetDatabaseInfoAsync(options);
34+
35+
if (dbInfo == null)
36+
{
37+
return;
38+
}
39+
40+
options.ProjectPath = project.FullPath;
41+
42+
if (!await LoadDataBaseObjectsAsync(options))
43+
{
44+
await VS.StatusBar.ClearAsync();
45+
return;
46+
}
47+
48+
await GenerateScriptAsync(options, dbInfo.ConnectionString);
49+
}
50+
catch (AggregateException ae)
51+
{
52+
foreach (var innerException in ae.Flatten().InnerExceptions)
53+
{
54+
VSHelper.ShowError(innerException.Message);
55+
}
56+
}
57+
catch (Exception exception)
58+
{
59+
VSHelper.ShowError(exception.Message);
60+
}
61+
finally
62+
{
63+
await VS.StatusBar.ClearAsync();
64+
}
65+
}
66+
67+
private static async Task GenerateScriptAsync(DataApiBuilderOptions options, string connectionString)
68+
{
69+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
70+
71+
await VS.StatusBar.ShowProgressAsync("Getting seed data", 1, 2);
72+
73+
var revEngRunner = new ProcessLauncher();
74+
75+
var parts = options.Tables.FirstOrDefault()?.Name.Split('.');
76+
77+
if (parts == null || parts.Length != 2)
78+
{
79+
VSHelper.ShowError("No table selected.");
80+
return;
81+
}
82+
83+
var tableName = parts[1];
84+
var schema = parts[0];
85+
86+
var result = await revEngRunner.CreateMergeScriptAsync(options.ProjectPath, connectionString, tableName, schema);
87+
88+
await VS.StatusBar.ShowProgressAsync("Getting seed data", 2, 2);
89+
90+
if (File.Exists(result))
91+
{
92+
await VS.Documents.OpenAsync(result);
93+
}
94+
}
95+
96+
private static async Task<List<TableModel>> GetTablesAsync(string connectionString)
97+
{
98+
var builder = new TableListBuilder(connectionString, DatabaseType.SQLServer, null);
99+
100+
return await builder.GetTableDefinitionsAsync();
101+
}
102+
103+
private static async Task<bool> LoadDataBaseObjectsAsync(DataApiBuilderOptions options)
104+
{
105+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
106+
107+
IEnumerable<TableModel> predefinedTables = null;
108+
109+
try
110+
{
111+
await VS.StatusBar.StartAnimationAsync(StatusAnimation.Build);
112+
113+
predefinedTables = await GetTablesAsync(options.ConnectionString);
114+
115+
predefinedTables = predefinedTables
116+
.Where(t => t.ObjectType == ObjectType.Table);
117+
}
118+
catch (InvalidOperationException ex)
119+
{
120+
VSHelper.ShowError($"{ex.Message}");
121+
return false;
122+
}
123+
finally
124+
{
125+
await VS.StatusBar.EndAnimationAsync(StatusAnimation.Build);
126+
}
127+
128+
var preselectedTables = new List<SerializationTableModel>();
129+
130+
await VS.StatusBar.ClearAsync();
131+
132+
var ptd = PackageManager.Package.GetView<IPickTablesDialog>()
133+
.AddTables(predefinedTables, new List<Schema>())
134+
.PreselectTables(preselectedTables);
135+
136+
var pickTablesResult = ptd.ShowAndAwaitUserResponse(true);
137+
138+
options.Tables = pickTablesResult.Payload.Objects.ToList();
139+
return pickTablesResult.ClosedByOK;
140+
}
141+
142+
private async Task<(DatabaseConnectionModel DatabaseModel, int FileGenerationMode, bool ImportSettings)> ChooseDataBaseConnectionAsync(DataApiBuilderOptions options)
143+
{
144+
var vsDataHelper = new VsDataHelper();
145+
var databaseList = await vsDataHelper.GetDataConnectionsAsync();
146+
147+
var psd = PackageManager.Package.GetView<IPickServerDatabaseDialog>();
148+
149+
if (databaseList != null && databaseList.Any())
150+
{
151+
psd.PublishConnections(databaseList.Select(m => new DatabaseConnectionModel
152+
{
153+
ConnectionName = m.Value.ConnectionName,
154+
ConnectionString = m.Value.ConnectionString,
155+
DatabaseType = m.Value.DatabaseType,
156+
DataConnection = m.Value.DataConnection,
157+
}));
158+
}
159+
160+
psd.PublishFileGenerationMode(GetCodeGenerationModes());
161+
162+
var pickDataSourceResult = psd.ShowAndAwaitUserResponse(true);
163+
if (!pickDataSourceResult.ClosedByOK)
164+
{
165+
return (null, 0, false);
166+
}
167+
168+
if (pickDataSourceResult.Payload.Connection != null)
169+
{
170+
options.ConnectionString = pickDataSourceResult.Payload.Connection.ConnectionString;
171+
options.DatabaseType = pickDataSourceResult.Payload.Connection.DatabaseType;
172+
}
173+
174+
return (pickDataSourceResult.Payload.Connection,
175+
pickDataSourceResult.Payload.CodeGenerationMode,
176+
pickDataSourceResult.Payload.GetDatabaseOptions);
177+
}
178+
179+
private static async Task<DatabaseConnectionModel> GetDatabaseInfoAsync(DataApiBuilderOptions options)
180+
{
181+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
182+
183+
var dbInfo = new DatabaseConnectionModel();
184+
185+
if (!string.IsNullOrEmpty(options.ConnectionString))
186+
{
187+
dbInfo.ConnectionString = options.ConnectionString;
188+
dbInfo.DatabaseType = options.DatabaseType;
189+
}
190+
191+
if (dbInfo.DatabaseType == DatabaseType.Undefined)
192+
{
193+
VSHelper.ShowError($"Unsupported provider");
194+
return null;
195+
}
196+
197+
return dbInfo;
198+
}
199+
200+
private static List<CodeGenerationItem> GetCodeGenerationModes()
201+
{
202+
var list = new List<CodeGenerationItem>
203+
{
204+
new CodeGenerationItem { Key = 0, Value = "Seed" },
205+
};
206+
return list;
207+
}
208+
}
209+
}

0 commit comments

Comments
 (0)