diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs index a99a1989..72cee108 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; using Microsoft.SqlServer.Management.Common; using Microsoft.SqlTools.Extensibility; using Microsoft.SqlTools.Hosting; @@ -23,6 +24,7 @@ using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts; using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes; using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel; using Microsoft.SqlTools.ServiceLayer.SqlContext; +using Microsoft.SqlTools.ServiceLayer.TableDesigner; using Microsoft.SqlTools.ServiceLayer.Utility; using Microsoft.SqlTools.ServiceLayer.Workspace; using Microsoft.SqlTools.Utility; @@ -381,6 +383,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer TreeNode node = session.Root.FindNodeByPath(nodePath); ExpandResponse response = null; + // Performance Optimization for table designer to load the database model earlier based on user configuration. + if (node.NodeTypeId == NodeTypes.Database && TableDesignerService.Instance.Settings.PreloadDatabaseModel) + { + // The operation below are not blocking, but just in case, wrapping it with a task run to make sure it has no impact on the node expansion time. + var _ = Task.Run(() => + { + try + { + var builder = ConnectionService.CreateConnectionStringBuilder(session.ConnectionInfo.ConnectionDetails); + builder.InitialCatalog = node.NodeValue; + builder.ApplicationName = TableDesignerService.TableDesignerApplicationName; + var azureToken = session.ConnectionInfo.ConnectionDetails.AzureAccountToken; + TableDesignerCacheManager.StartDatabaseModelInitialization(builder.ToString(), azureToken); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Warning, $"Failed to start database initialization for table designer: {ex.Message}"); + } + }); + } + // This node was likely returned from a different node provider. Ignore expansion and return an empty array // since we don't need to add any nodes under this section of the tree. if (node == null) diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs index ce92841f..d505b92f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs @@ -22,6 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlContext IntelliSense = new IntelliSenseSettings(); QueryExecutionSettings = new QueryExecutionSettings(); Format = new FormatterSettings(); + TableDesigner = new TableDesignerSettings(); } } @@ -48,5 +49,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlContext /// [JsonProperty("objectExplorer")] public ObjectExplorerSettings ObjectExplorer { get; set; } + + /// + /// Gets or sets the table designer settings + /// + [JsonProperty("tableDesigner")] + public TableDesignerSettings TableDesigner { get; set; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs new file mode 100644 index 00000000..b252843f --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.SqlTools.ServiceLayer.SqlContext +{ + /// + /// Contract for receiving table designer settings as part of workspace settings + /// + public class TableDesignerSettings + { + /// + /// Whether the database model should be preloaded to make the initial launch quicker. + /// + public bool PreloadDatabaseModel { get; set; } = false; + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs index 8ee9b1ef..77640139 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs @@ -14,6 +14,7 @@ using Microsoft.Data.Tools.Sql.DesignServices; using Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts; using Dac = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; using STSHost = Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost; +using Microsoft.SqlTools.ServiceLayer.SqlContext; namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { @@ -32,6 +33,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { } + public TableDesignerSettings Settings { get; private set; } = new TableDesignerSettings(); + /// /// Gets the singleton instance object /// @@ -61,7 +64,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner this.ServiceHost.SetRequestHandler(GenerateScriptRequest.Type, HandleGenerateScriptRequest); this.ServiceHost.SetRequestHandler(GeneratePreviewReportRequest.Type, HandleGeneratePreviewReportRequest); this.ServiceHost.SetRequestHandler(DisposeTableDesignerRequest.Type, HandleDisposeTableDesignerRequest); + Workspace.WorkspaceService.Instance.RegisterConfigChangeCallback(UpdateSettings); + } + + internal Task UpdateSettings(SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext) + { + Settings.PreloadDatabaseModel = newSettings.MssqlTools.TableDesigner.PreloadDatabaseModel; + return Task.FromResult(0); + } + private Task HandleRequest(RequestContext requestContext, Func action) { // The request handling will take some time to return, we need to use a separate task to run the request handler so that it won't block the main thread.