diff --git a/content/common/CSharpScripts/Advanced/script-convert-dlol-to-import.md b/content/common/CSharpScripts/Advanced/script-convert-dlol-to-import.md new file mode 100644 index 0000000..6f2f240 --- /dev/null +++ b/content/common/CSharpScripts/Advanced/script-convert-dlol-to-import.md @@ -0,0 +1,282 @@ +--- +uid: script-convert-import-to-dlol +title: Convert Direct Lake on OneLake to import +author: Morten Lønskov +updated: 2025-06-25 +applies_to: + versions: + - version: 2.x + - version: 3.x +--- +# Convert Import to Direct Lake on OneLake + +## Script Purpose + +This script converts Direct Lake on OneLake (DL/OL) to Import mode tables. As laid out in the [Direct Lake guidance article](xref:direct-lake-guidance), we need to replace the partition(s) on such tables with a single [EntityPartition](https://learn.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.entitypartitionsource?view=analysisservices-dotnet), which specifies the name and schema of the table/materialized view in the Fabric Lakehouse or Warehouse, while referencing a Shared Expression that uses the [`AzureStorage.DataLake`](https://learn.microsoft.com/en-us/powerquery-m/azurestorage-datalake) (OneLake) connector. + +## Prerequisites + +You will need the **SQL Endpoint** as well as the **Name** of your Fabric Warehouse or Lakehouse. Both can be found in the Fabric portal. + +You will also need to know the **Schema** of the table/materialized view you wish to connect to. + + +## Script + +### Convert Import mode tables to Direct Lake on OneLake + +```csharp +// =================================================================================== +// Convert Direct Lake on OneLake tables back to Import mode +// ---------------------------------------- +// This scripts converts the selected or all tables from Direct Lake on OneLake to import +// It adds a shared expression named SQLEndpoint and replaces the existing DatabaseQuery if it no longer needed +// =================================================================================== +using System; +using System.Linq; +using System.Collections.Generic; +using System.Windows.Forms; +using System.Drawing; + +// ------------------------------------------------------------------- +// 1) Scope‐picker dialog +// ------------------------------------------------------------------- +public class ScopeSelectionDialog : Form +{ + public enum ScopeOption { OnlySelected, All, Cancel } + public ScopeOption SelectedOption { get; private set; } + + public ScopeSelectionDialog(int selectedCount, int totalCount) + { + Text = "Choose tables to convert"; + AutoSize = true; AutoSizeMode = AutoSizeMode.GrowAndShrink; + StartPosition = FormStartPosition.CenterParent; + Padding = new Padding(20); + + var layout = new TableLayoutPanel { + ColumnCount = 1, Dock = DockStyle.Fill, + AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink + }; + Controls.Add(layout); + + layout.Controls.Add(new Label { + Text = $"You have {selectedCount} table(s) selected,\nand {totalCount} Direct Lake table(s) in the model.", + AutoSize = true, TextAlign = ContentAlignment.MiddleLeft + }); + + var panel = new FlowLayoutPanel { + FlowDirection = FlowDirection.LeftToRight, + Dock = DockStyle.Fill, AutoSize = true, + Padding = new Padding(0, 20, 0, 0) + }; + + var btnOnly = new Button { + Text = "Only selected tables", AutoSize = true, + DialogResult = DialogResult.OK + }; + btnOnly.Click += (s, e) => SelectedOption = ScopeOption.OnlySelected; + + var btnAll = new Button { + Text = "All tables", AutoSize = true, + DialogResult = DialogResult.Retry + }; + btnAll.Click += (s, e) => SelectedOption = ScopeOption.All; + + var btnCancel = new Button { + Text = "Cancel", AutoSize = true, + DialogResult = DialogResult.Cancel + }; + btnCancel.Click += (s, e) => SelectedOption = ScopeOption.Cancel; + + panel.Controls.AddRange(new Control[] { btnOnly, btnAll, btnCancel }); + layout.Controls.Add(panel); + + AcceptButton = btnOnly; + CancelButton = btnCancel; + } +} + +// ------------------------------------------------------------------- +// 2) SQL‐import dialog (schema now required) +// ------------------------------------------------------------------- +public class SqlImportDialog : Form +{ + public TextBox SqlEndpoint { get; } + public TextBox DatabaseName { get; } + public TextBox Schema { get; } + private Button okButton; + + public SqlImportDialog(string endpoint, string db, string schema) + { + Text = "Convert Direct Lake → Import"; + AutoSize = true; AutoSizeMode = AutoSizeMode.GrowAndShrink; + StartPosition = FormStartPosition.CenterParent; + Padding = new Padding(20); + + var layout = new TableLayoutPanel { + ColumnCount = 1, Dock = DockStyle.Fill, + AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink + }; + Controls.Add(layout); + + // Endpoint + layout.Controls.Add(new Label { Text = "SQL Analytics Endpoint:", AutoSize = true }); + SqlEndpoint = new TextBox { Width = 800, Text = endpoint }; + layout.Controls.Add(SqlEndpoint); + + // Database + layout.Controls.Add(new Label { + Text = "Lakehouse/Warehouse Name:", Padding = new Padding(0, 20, 0, 0), + AutoSize = true + }); + DatabaseName = new TextBox { Width = 800, Text = db }; + layout.Controls.Add(DatabaseName); + + // Schema (required) + layout.Controls.Add(new Label { + Text = "Schema:", Padding = new Padding(0, 20, 0, 0), + AutoSize = true + }); + Schema = new TextBox { Width = 800, Text = schema }; + layout.Controls.Add(Schema); + + // Buttons + var panel = new FlowLayoutPanel { + FlowDirection = FlowDirection.RightToLeft, + Dock = DockStyle.Fill, AutoSize = true, + Padding = new Padding(0, 20, 0, 0) + }; + okButton = new Button { + Text = "OK", DialogResult = DialogResult.OK, + AutoSize = true, Enabled = false + }; + var cancel = new Button { + Text = "Cancel", DialogResult = DialogResult.Cancel, + AutoSize = true + }; + panel.Controls.AddRange(new Control[] { okButton, cancel }); + layout.Controls.Add(panel); + + AcceptButton = okButton; + CancelButton = cancel; + + // Only enable OK when all three fields are non-empty + SqlEndpoint.TextChanged += Validate; + DatabaseName.TextChanged += Validate; + Schema.TextChanged += Validate; + Shown += (s,e) => Validate(s,e); + } + + private void Validate(object sender, EventArgs e) + { + okButton.Enabled = + !string.IsNullOrWhiteSpace(SqlEndpoint.Text) && + !string.IsNullOrWhiteSpace(DatabaseName.Text) && + !string.IsNullOrWhiteSpace(Schema.Text); + } +} + +// ------------------------------------------------------------------- +// 3) Main conversion logic +// ------------------------------------------------------------------- +WaitFormVisible = false; +Application.UseWaitCursor = false; + +// 3.1) Find all Direct Lake tables +var allDirectLake = Model.Tables + .Where(t => t.Partitions.Count == 1 + && t.Partitions[0].SourceType == PartitionSourceType.Entity + && t.Partitions[0].Mode == ModeType.DirectLake) + .ToList(); + +// 3.2) And those you’ve selected +var selectedDirect = Selected.Tables + .Cast