diff --git a/SetUpAggs/AW Internet Sales/AdventureWorksAggs.smproj b/SetUpAggs/AW Internet Sales/AdventureWorksAggs.smproj index 963435a..59b4ba8 100644 --- a/SetUpAggs/AW Internet Sales/AdventureWorksAggs.smproj +++ b/SetUpAggs/AW Internet Sales/AdventureWorksAggs.smproj @@ -24,7 +24,7 @@ Default - asazure://aspaastest14.asazure-int.windows.net/sukanyasaltsrc1 + localhost\SQL2016 Developer Unknown AdventureWorksAggs diff --git a/SetUpAggs/AdventureWorksAggsProvider/AdventureWorksAggsProvider.smproj b/SetUpAggs/AdventureWorksAggsProvider/AdventureWorksAggsProvider.smproj index 13c4019..27f7cc4 100644 --- a/SetUpAggs/AdventureWorksAggsProvider/AdventureWorksAggsProvider.smproj +++ b/SetUpAggs/AdventureWorksAggsProvider/AdventureWorksAggsProvider.smproj @@ -24,7 +24,7 @@ Default - asazure://aspaastest14.asazure-int.windows.net/sukanyasaltsrc1 + localhost\SQL2016 Developer Unknown AdventureWorksAggsProvider diff --git a/SetUpAggs/AggsConfig.json b/SetUpAggs/AggsConfig.json index 3460c5e..80f6451 100644 --- a/SetUpAggs/AggsConfig.json +++ b/SetUpAggs/AggsConfig.json @@ -1,74 +1,37 @@ { - "database": { - "name": "AdventureWorksAggsProvider_PH", - "tables": [ - { - "name": "DimGeography", - "mode": "Dual" - }, - { - "name": "DimCustomer", - "mode": "Dual" - }, - { - "name": "DimDate", - "mode": "Dual" - }, - { - "name": "DimProductSubcategory", - "mode": "Dual" - }, - { - "name": "DimProductCategory", - "mode": "Dual" - }, - { - "name": "FactInternetSalesAgg", - "mode": "Import", - "aggregationRules": [ - { - "aggTableColumn": "OrderDateKey", - "summarization": "GroupBy", - "detailTable": "FactInternetSales", - "detailTableColumn": "OrderDateKey" - }, - { - "aggTableColumn": "CustomerKey", - "summarization": "GroupBy", - "detailTable": "FactInternetSales", - "detailTableColumn": "CustomerKey" - }, - { - "aggTableColumn": "ProductSubcategoryKey", - "summarization": "GroupBy", - "detailTable": "DimProduct", - "detailTableColumn": "ProductSubcategoryKey" - }, - { - "aggTableColumn": "SalesAmount_Sum", - "summarization": "Sum", - "detailTable": "FactInternetSales", - "detailTableColumn": "SalesAmount" - }, - { - "aggTableColumn": "UnitPrice_Sum", - "summarization": "Min", - "detailTable": "FactInternetSales", - "detailTableColumn": "UnitPrice" - }, - { - "aggTableColumn": "UnitPrice_Count", - "summarization": "Count", - "detailTable": "FactInternetSales", - "detailTableColumn": "UnitPrice" - }, - { - "aggTableColumn": "FactInternetSales_Count", - "summarization": "CountTableRows", - "detailTable": "FactInternetSales" - } - ] - } - ] - } + "database": { + "name": "AdventureWorksAggsProvider", + "tables": [ + { + "name": "DimGeography", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimCustomer", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimDate", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimProductSubcategory", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimProductCategory", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "FactInternetSalesAgg", + "mode": "DirectQuery", + "refreshType": "Full" + } + ] + } } \ No newline at end of file diff --git a/SetUpAggs/AggsConfig2.json b/SetUpAggs/AggsConfig2.json deleted file mode 100644 index 0c40309..0000000 --- a/SetUpAggs/AggsConfig2.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "database": { - "name": "AdventureWorksAggsProvider_PH", - "tables": [ - { - "name": "DimGeography", - "mode": "Dual" - }, - { - "name": "DimCustomer", - "mode": "Dual" - }, - { - "name": "DimDate", - "mode": "Dual" - }, - { - "name": "DimProductSubcategory", - "mode": "Dual" - }, - { - "name": "DimProductCategory", - "mode": "Dual" - }, - { - "name": "FactInternetSalesAgg", - "mode": "Import", - "aggregationRules": [ - { - "aggTableColumn": "OrderDateKey", - "summarization": "GroupBy", - "detailTable": "FactInternetSales", - "detailTableColumn": "OrderDateKey" - }, - { - "aggTableColumn": "CustomerKey", - "summarization": "GroupBy", - "detailTable": "FactInternetSales", - "detailTableColumn": "CustomerKey" - }, - { - "aggTableColumn": "ProductSubcategoryKey", - "summarization": "GroupBy", - "detailTable": "DimProduct", - "detailTableColumn": "ProductSubcategoryKey" - }, - { - "aggTableColumn": "SalesAmount_Sum", - "summarization": "Sum", - "detailTable": "FactInternetSales", - "detailTableColumn": "SalesAmount" - }, - { - "aggTableColumn": "UnitPrice_Sum", - "summarization": "Sum", - "detailTable": "FactInternetSales", - "detailTableColumn": "UnitPrice" - }, - { - "aggTableColumn": "UnitPrice_Count", - "summarization": "Count", - "detailTable": "FactInternetSales", - "detailTableColumn": "UnitPrice" - }, - { - "aggTableColumn": "FactInternetSales_Count", - "summarization": "CountTableRows", - "detailTable": "FactInternetSales" - } - ] - } - ] - } -} \ No newline at end of file diff --git a/SetUpAggs/AggsConfig_SetAggs1.json b/SetUpAggs/AggsConfig_SetAggs1.json new file mode 100644 index 0000000..c6a9cae --- /dev/null +++ b/SetUpAggs/AggsConfig_SetAggs1.json @@ -0,0 +1,75 @@ +{ + "database": { + "name": "AdventureWorksAggsProvider", + "tables": [ + { + "name": "DimGeography", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimCustomer", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimDate", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimProductSubcategory", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimProductCategory", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "FactInternetSalesAgg", + "mode": "Import", + "refreshType": "Full", + "aggregationRules": [ + { + "aggTableColumn": "OrderDateKey", + "summarization": "GroupBy", + "detailTable": "FactInternetSales", + "detailTableColumn": "OrderDateKey" + }, + { + "aggTableColumn": "CustomerKey", + "summarization": "GroupBy", + "detailTable": "FactInternetSales", + "detailTableColumn": "CustomerKey" + }, + { + "aggTableColumn": "ProductSubcategoryKey", + "summarization": "GroupBy", + "detailTable": "DimProduct", + "detailTableColumn": "ProductSubcategoryKey" + }, + { + "aggTableColumn": "SalesAmount_Sum", + "summarization": "Sum", + "detailTable": "FactInternetSales", + "detailTableColumn": "SalesAmount" + }, + { + "aggTableColumn": "UnitPrice_Sum", + "summarization": "Min", + "detailTable": "FactInternetSales", + "detailTableColumn": "UnitPrice" + }, + { + "aggTableColumn": "UnitPrice_Count", + "summarization": "Count", + "detailTable": "FactInternetSales", + "detailTableColumn": "UnitPrice" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/SetUpAggs/AggsConfig_SetAggs2.json b/SetUpAggs/AggsConfig_SetAggs2.json new file mode 100644 index 0000000..d6c2736 --- /dev/null +++ b/SetUpAggs/AggsConfig_SetAggs2.json @@ -0,0 +1,74 @@ +{ + "database": { + "name": "AdventureWorksAggsProvider", + "tables": [ + { + "name": "DimGeography", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimCustomer", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimDate", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimProductSubcategory", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimProductCategory", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "FactInternetSalesAgg", + "mode": "Import", + "refreshType": "Full", + "aggregationRules": [ + { + "aggTableColumn": "OrderDateKey", + "summarization": "GroupBy", + "detailTable": "FactInternetSales", + "detailTableColumn": "OrderDateKey" + }, + { + "aggTableColumn": "CustomerKey", + "summarization": "GroupBy", + "detailTable": "FactInternetSales", + "detailTableColumn": "CustomerKey" + }, + { + "aggTableColumn": "ProductSubcategoryKey", + "summarization": "GroupBy", + "detailTable": "DimProduct", + "detailTableColumn": "ProductSubcategoryKey" + }, + { + "aggTableColumn": "SalesAmount_Sum", + "summarization": "Sum", + "detailTable": "FactInternetSales", + "detailTableColumn": "SalesAmount" + }, + { + "aggTableColumn": "UnitPrice_Sum", + "summarization": "Sum", + "detailTable": "FactInternetSales", + "detailTableColumn": "UnitPrice" + }, + { + "aggTableColumn": "FactInternetSales_Count", + "summarization": "CountTableRows", + "detailTable": "FactInternetSales" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/SetUpAggs/AggsConfig_SetDQ.json b/SetUpAggs/AggsConfig_SetDQ.json new file mode 100644 index 0000000..fc76ecd --- /dev/null +++ b/SetUpAggs/AggsConfig_SetDQ.json @@ -0,0 +1,37 @@ +{ + "database": { + "name": "AdventureWorksAggsProvider", + "tables": [ + { + "name": "DimGeography", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimCustomer", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimDate", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimProductSubcategory", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "DimProductCategory", + "mode": "DirectQuery", + "refreshType": "Full" + }, + { + "name": "FactInternetSalesAgg", + "mode": "DirectQuery", + "refreshType": "Full" + } + ] + } +} \ No newline at end of file diff --git a/SetUpAggs/Program.cs b/SetUpAggs/Program.cs index 7a5e16b..4ab461e 100644 --- a/SetUpAggs/Program.cs +++ b/SetUpAggs/Program.cs @@ -66,6 +66,9 @@ namespace SetUpAggs [JsonProperty("mode")] public string Mode { get; set; } + [JsonProperty("refreshType")] + public string RefreshType { get; set; } + [JsonProperty("aggregationRules", NullValueHandling = NullValueHandling.Ignore)] public AggregationRule[] AggregationRules { get; set; } } @@ -287,8 +290,9 @@ namespace SetUpAggs /// private void Connect(string serverName) { + // Changed this line to force login dialogs //string connectionString = $"Provider=MSOLAP;Data Source={args.Server};"; - string connectionString = $"Provider=MSOLAP;Data Source={serverName};Integrated Security=SSPI;Persist Security Info=True;"; + string connectionString = $"Provider=MSOLAP;Data Source={serverName};Persist Security Info=True;"; server.Connect(connectionString); database = server.Databases.FindByName(aggsConfig.Database.Name); @@ -411,12 +415,17 @@ namespace SetUpAggs { Console.ForegroundColor = ConsoleColor.White; Console.Write($"Refreshing table [{tableObj.Name}] "); - tableObj.RequestRefresh(RefreshType.Full); + + Table tableConfig = aggsConfig.Database.Tables.First(x => x.Name == tableObj.Name); + var refreshType = (RefreshType)Enum.Parse(typeof(RefreshType), tableConfig.RefreshType); + tableObj.RequestRefresh(refreshType); + Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("COMPLETE"); } - database.Model.SaveChanges(); + // Removed this line which was throwing errors on large models, and it seems to commit the changes without it + // database.Model.SaveChanges(); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("Refreshing tables - end: " + DateTime.Now.ToString("hh:mm:ss tt")); diff --git a/SetUpAggs/README.md b/SetUpAggs/README.md new file mode 100644 index 0000000..0d38565 --- /dev/null +++ b/SetUpAggs/README.md @@ -0,0 +1,110 @@ +# SetUpAggs + +This utility is designed to assist in updating a Power BI dataset to utilize the Composite Model and Aggregations features. The utility will connect to a Power BI workspace through the XMLA endpoint and read in a configuration file, this configuration file will specify the database and associated tables to update the Composite Model and Aggregations properties. + +It will upgrade the model to Compatibility Level 1465, this change is not reversible via this utility. The utility will only update the metadata of tables listed in the configuration file, but it will both add and remove Aggregation column definitions, so that the model metadata will match the configuration file. Partition mode changes will be applied to all the partitions defined on the table. + +## Example Usage +SetUpAggs.exe apply -Server [PowerBI workspace URL] -ConfigFile AggsConfig.json + +## Steps +* Parse command line arguments, show basic help +* Connect to model +* Validate configuration file against the model, exit with relevant error message if issue is found in configuration or model +* Update model compatibility level if current compatibility level is below 1465 +* Apply configuration changes to model + * For each table + * For each partition, update partition mode to Dual, DirectQuery, Import, or Default as specified in config + * For each column, remove any AlternateOf definitions that do not match an aggregation rule in the config + * For each rule, add the AlternateOf definition to the model if it does not already exist +* If changes were made to the model, run the ExpandFull on the model +* If changes were made to the model, refresh the tables that were modified + +## Configuration File Example + +Accepted values for enumeration fields: + +database.tables[].mode - Default, DirectQuery, Dual, Import +database.tables[].refreshType - Add, Automatic, Calculate, ClearValues, DataOnly, Defragment, Full +database.tables[].aggregationRules[].summarization - Count, GroupBy, Max, Min, Sum, CountTableRows + +```json +{ + "database": { + "name": "AdventureWorksAggsProvider", + "tables": [ + { + "name": "DimGeography", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimCustomer", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimDate", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimProductSubcategory", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "DimProductCategory", + "mode": "Dual", + "refreshType": "Full" + }, + { + "name": "FactInternetSalesAgg", + "mode": "Import", + "refreshType": "Full", + "aggregationRules": [ + { + "aggTableColumn": "OrderDateKey", + "summarization": "GroupBy", + "detailTable": "FactInternetSales", + "detailTableColumn": "OrderDateKey" + }, + { + "aggTableColumn": "CustomerKey", + "summarization": "GroupBy", + "detailTable": "FactInternetSales", + "detailTableColumn": "CustomerKey" + }, + { + "aggTableColumn": "ProductSubcategoryKey", + "summarization": "GroupBy", + "detailTable": "DimProduct", + "detailTableColumn": "ProductSubcategoryKey" + }, + { + "aggTableColumn": "SalesAmount_Sum", + "summarization": "Sum", + "detailTable": "FactInternetSales", + "detailTableColumn": "SalesAmount" + }, + { + "aggTableColumn": "UnitPrice_Sum", + "summarization": "Sum", + "detailTable": "FactInternetSales", + "detailTableColumn": "UnitPrice" + }, + { + "aggTableColumn": "FactInternetSales_Count", + "summarization": "CountTableRows", + "detailTable": "FactInternetSales" + } + ] + } + ] + } +} +``` + + + + diff --git a/SetUpAggs/SetUpAggs.csproj b/SetUpAggs/SetUpAggs.csproj index d6819e0..e0f1aab 100644 --- a/SetUpAggs/SetUpAggs.csproj +++ b/SetUpAggs/SetUpAggs.csproj @@ -11,6 +11,21 @@ v4.6.1 512 true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true AnyCPU @@ -67,8 +82,25 @@ + + + + + + + + + False + Microsoft .NET Framework 4.6.1 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + \ No newline at end of file