Skip to content

Commit c01b9d9

Browse files
Enable VPAX extraction on non-Windows platforms (#126)
* Remove `windows` platform target * Use DbConnectionStringBuilder instead of OleDb * Remove `System.Data.OleDb` package reference * Fix build error
1 parent 7a1209b commit c01b9d9

11 files changed

+76
-72
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Data.Common;
3+
using System.Globalization;
4+
5+
namespace Dax.Model.Extractor.Data
6+
{
7+
public static class ConnectionStringUtils
8+
{
9+
public static string GetDataSource(string connectionString) => GetValue(connectionString, ConnectionStringKeywords.DataSource);
10+
11+
public static string GetInitialCatalog(string connectionString) => GetValue(connectionString, ConnectionStringKeywords.InitialCatalog);
12+
13+
public static string GetConnectionString(string serverNameOrConnectionString, string databaseName)
14+
{
15+
var builder = new DbConnectionStringBuilder(useOdbcRules: false);
16+
try {
17+
builder.ConnectionString = serverNameOrConnectionString;
18+
}
19+
catch {
20+
// Assume servername
21+
builder[ConnectionStringKeywords.Provider] = "MSOLAP";
22+
builder[ConnectionStringKeywords.DataSource] = serverNameOrConnectionString;
23+
}
24+
builder[ConnectionStringKeywords.InitialCatalog] = databaseName;
25+
return builder.ConnectionString;
26+
}
27+
28+
private static string GetValue(string connectionString, string keyword)
29+
{
30+
var builder = new DbConnectionStringBuilder(useOdbcRules: false);
31+
builder.ConnectionString = connectionString;
32+
33+
if (builder.TryGetValue(keyword, out object value))
34+
return ((IConvertible)value).ToString(CultureInfo.InvariantCulture);
35+
36+
return string.Empty; // default to empty string to keep the result consistent with the OleDbConnectionStringBuilder
37+
}
38+
}
39+
40+
internal static class ConnectionStringKeywords
41+
{
42+
public const string Provider = "Provider";
43+
public const string DataSource = "Data Source";
44+
public const string InitialCatalog = "Initial Catalog";
45+
}
46+
}

src/Dax.Model.Extractor/Data/IDbConnectionExtensions.cs

-20
This file was deleted.

src/Dax.Model.Extractor/Dax.Model.Extractor.csproj

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net462;netcoreapp3.1;net6.0-windows</TargetFrameworks>
4+
<TargetFrameworks>net462;netcoreapp3.1;net6.0</TargetFrameworks>
55
<IsPackable>true</IsPackable>
66
</PropertyGroup>
77

@@ -22,13 +22,12 @@
2222

2323
<ItemGroup>
2424
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
25-
<PackageReference Include="System.Data.OleDb" />
2625
</ItemGroup>
2726
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
2827
<PackageReference Include="Microsoft.AnalysisServices.retail.amd64" />
2928
<PackageReference Include="Microsoft.AnalysisServices.AdomdClient.retail.amd64" />
3029
</ItemGroup>
31-
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' OR '$(TargetFramework)' == 'net6.0-windows'">
30+
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' OR '$(TargetFramework)' == 'net6.0'">
3231
<PackageReference Include="Microsoft.AnalysisServices.NetCore.retail.amd64" />
3332
<PackageReference Include="Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64" />
3433
</ItemGroup>

src/Dax.Model.Extractor/DmvExtractor.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ public class DmvExtractor
3434

3535
protected IDbCommand CreateCommand(string commandText)
3636
{
37-
return Connection.CreateCommand(commandText);
37+
var command = Connection.CreateCommand();
38+
command.CommandText = commandText;
39+
return command;
3840
}
3941

4042
public DmvExtractor(Dax.Metadata.Model daxModel, IDbConnection connection, string serverName, string databaseName, string extractorApp, string extractorVersion)

src/Dax.Model.Extractor/StatExtractor.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ private StatExtractor(Dax.Metadata.Model daxModel, IDbConnection connection)
1919

2020
protected IDbCommand CreateCommand(string commandText)
2121
{
22-
return Connection.CreateCommand(commandText);
22+
var command = Connection.CreateCommand();
23+
command.CommandText = commandText;
24+
return command;
2325
}
2426

2527
// UpdateStatisticsModel has been marked as obsolete because its usage may require rerunning the DMVs for models with DirectLake partitions. Since this logic should be handled by the library, we may consider removing it from the public APIs in a future release.

src/Dax.Model.Extractor/TomExtractor.cs

+7-33
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using Dax.Metadata;
2+
using Dax.Model.Extractor.Data;
23
using Microsoft.AnalysisServices.AdomdClient;
4+
using Newtonsoft.Json.Linq;
35
using System;
4-
using System.Data.OleDb;
6+
using System.Data.Common;
7+
using System.Globalization;
58
using System.Linq;
69
using Tom = Microsoft.AnalysisServices.Tabular;
710

@@ -288,7 +291,7 @@ public static Dax.Metadata.Model GetDaxModel(string connectionString, string app
288291
var database = GetDatabase(connectionString);
289292
Tom.Model tomModel = database.Model;
290293
string databaseName = database.Name;
291-
string serverName = GetDataSource(connectionString);
294+
string serverName = ConnectionStringUtils.GetDataSource(connectionString);
292295

293296
var daxModel = TomExtractor.GetDaxModel(tomModel, applicationName, applicationVersion);
294297

@@ -312,18 +315,6 @@ public static Dax.Metadata.Model GetDaxModel(string connectionString, string app
312315
return daxModel;
313316
}
314317

315-
private static string GetDataSource(string connectionString)
316-
{
317-
var builder = new OleDbConnectionStringBuilder(connectionString);
318-
return builder.DataSource;
319-
}
320-
321-
private static string GetInitialCatalog(string connectionString)
322-
{
323-
var builder = new OleDbConnectionStringBuilder(connectionString);
324-
builder.TryGetValue("Initial Catalog", out object initialCatalog);
325-
return initialCatalog.ToString();
326-
}
327318
public static Tom.Database GetDatabase(string serverName, string databaseName)
328319
{
329320
Tom.Server server = new();
@@ -337,7 +328,7 @@ public static Tom.Database GetDatabase(string connectionString)
337328
{
338329
Tom.Server server = new();
339330
server.Connect(connectionString);
340-
var databaseName = GetInitialCatalog(connectionString);
331+
var databaseName = ConnectionStringUtils.GetInitialCatalog(connectionString);
341332
Tom.Database db = server.Databases.FindByName(databaseName);
342333
// if db is null either it does not exist or we do not have admin rights to it
343334
return db ?? throw new ArgumentException($"The database '{databaseName}' could not be found. Either it does not exist or you do not have admin rights to it.");
@@ -350,7 +341,7 @@ public static Dax.Metadata.Model GetDaxModel(string serverName, string databaseN
350341

351342
var daxModel = TomExtractor.GetDaxModel(tomModel, applicationName, applicationVersion);
352343

353-
string connectionString = GetConnectionString(serverName, databaseName);
344+
string connectionString = ConnectionStringUtils.GetConnectionString(serverName, databaseName);
354345

355346
using (AdomdConnection connection = new(connectionString))
356347
{
@@ -371,22 +362,5 @@ public static Dax.Metadata.Model GetDaxModel(string serverName, string databaseN
371362
}
372363
return daxModel;
373364
}
374-
375-
private static string GetConnectionString(string dataSourceOrConnectionString, string databaseName)
376-
{
377-
OleDbConnectionStringBuilder csb = new();
378-
try
379-
{
380-
csb.ConnectionString = dataSourceOrConnectionString;
381-
}
382-
catch
383-
{
384-
// Assume servername
385-
csb.Provider = "MSOLAP";
386-
csb.DataSource = dataSourceOrConnectionString;
387-
}
388-
csb["Initial Catalog"] = databaseName;
389-
return csb.ConnectionString;
390-
}
391365
}
392366
}

src/Dax.Vpax.CLI/Commands/ExportCommandOptions.cs

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.CommandLine;
2-
using System.Data.OleDb;
2+
using System.Data.Common;
33

44
namespace Dax.Vpax.CLI.Commands;
55

@@ -11,12 +11,14 @@ internal static class ExportCommandOptions
1111
parse: (result) =>
1212
{
1313
var connectionString = result.Tokens.Single().Value;
14-
15-
var builder = new OleDbConnectionStringBuilder(connectionString);
16-
if (!builder.ContainsKey("Initial Catalog"))
17-
result.ErrorMessage = "The connection string does not contain the 'Initial Catalog' property.";
18-
19-
return connectionString;
14+
{
15+
var builder = new DbConnectionStringBuilder(useOdbcRules: false);
16+
builder.ConnectionString = connectionString;
17+
18+
if (!builder.ContainsKey("Initial Catalog"))
19+
result.ErrorMessage = "The connection string does not contain the 'Initial Catalog' property.";
20+
}
21+
return connectionString; // always return the original value
2022
});
2123

2224
public static readonly Argument<string> PathArgument = new(

src/Directory.Packages.props

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
<PackageVersion Include="Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64" Version="$(MicrosoftAnalysisServicesVersion)" />
1313
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
1414
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
15-
<PackageVersion Include="System.Data.OleDb" Version="6.0.0" />
1615
<PackageVersion Include="System.IO.Packaging" Version="6.0.0" />
1716
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
1817
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />

utils/TestDaxWpf/MainWindow.xaml.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,17 @@ public static Dax.Metadata.Model GetDaxModel(string serverName, string databaseN
6060
server.Connect(serverName);
6161
Microsoft.AnalysisServices.Database db = server.Databases[databaseName];
6262
Microsoft.AnalysisServices.Tabular.Model tomModel = db.Model;
63-
var daxModel = Dax.Metadata.Extractor.TomExtractor.GetDaxModel(tomModel, "TestDaxModel", "0.1");
63+
var daxModel = Dax.Model.Extractor.TomExtractor.GetDaxModel(tomModel, "TestDaxModel", "0.1");
6464

6565
var connectionString = GetConnectionString(serverName, databaseName);
6666

6767
using (var connection = new AdomdConnection(connectionString)) {
6868
// Populate statistics from DMV
69-
Dax.Metadata.Extractor.DmvExtractor.PopulateFromDmv(daxModel, connection, serverName, databaseName, "TestDaxModel", "0.1");
69+
Dax.Model.Extractor.DmvExtractor.PopulateFromDmv(daxModel, connection, serverName, databaseName, "TestDaxModel", "0.1");
7070

7171
// Populate statistics by querying the data model
7272
if (readStatisticsFromData) {
73-
Dax.Metadata.Extractor.StatExtractor.UpdateStatisticsModel(daxModel, connection, 10);
73+
Dax.Model.Extractor.StatExtractor.UpdateStatisticsModel(daxModel, connection, 10);
7474
}
7575
}
7676
return daxModel;

utils/TestPowerBI/Form1.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private void TestPbiShared(string name, string id)
221221
//Console.WriteLine("Connection open");
222222

223223
Dax.Metadata.Model m = new Dax.Metadata.Model();
224-
Dax.Metadata.Extractor.DmvExtractor.PopulateFromDmv(m, conn, serverName, databaseName, "Test", "0.1");
224+
Dax.Model.Extractor.DmvExtractor.PopulateFromDmv(m, conn, serverName, databaseName, "Test", "0.1");
225225

226226
Dax.Vpax.Tools.VpaxTools.ExportVpax(@"c:\temp\" + name + ".vpax",m);
227227
}

utils/TestWpfPowerBI/MainWindow.xaml.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,8 @@ private Dax.ViewModel.VpaModel GetVpaModel(string groupName, string datasetName,
322322
Dax.Metadata.Model m = new Dax.Metadata.Model();
323323
// NOTE: groupName is the serverName in the arguments
324324
// datasetName is the databaseName in the arguments
325-
Dax.Metadata.Extractor.DmvExtractor.PopulateFromDmv(m, conn, groupName, datasetName, "Test", "0.1");
326-
Dax.Metadata.Extractor.StatExtractor.UpdateStatisticsModel(m, conn, 4);
325+
Dax.Model.Extractor.DmvExtractor.PopulateFromDmv(m, conn, groupName, datasetName, "Test", "0.1");
326+
Dax.Model.Extractor.StatExtractor.UpdateStatisticsModel(m, conn, 4);
327327
return new Dax.ViewModel.VpaModel(m);
328328
}
329329

0 commit comments

Comments
 (0)