From 1ec297efe2beb20bc3f491ca35b3bcffdaf0e236 Mon Sep 17 00:00:00 2001 From: Leila Lali Date: Fri, 1 Dec 2017 14:49:42 -0800 Subject: [PATCH] improving OE tables expand (#555) * improving OE tables expand for dw database --- .../ObjectExplorer/Nodes/ChildFactory.cs | 4 +-- .../Nodes/NodeObservableCollection.cs | 15 ++++++++- .../SmoModel/SmoChildFactoryBase.cs | 33 ++++++++++++++++--- .../SmoModel/SmoDatabaseCustomNode.cs | 15 +++++---- .../SmoModel/SmoKeyCustomNode.cs | 12 +++---- .../SmoModel/SmoLoginCustomNode.cs | 4 +-- .../SmoModel/SmoParamterCustomNode.cs | 16 ++++----- .../SmoModel/SmoTableCustomNode.cs | 8 ++--- .../SmoModel/SmoTriggerCustomNode.cs | 12 +++---- .../SmoModel/SmoUserCustomNode.cs | 4 +-- .../Baselines/AllSqlObjects.txt | 4 +-- 11 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs index 0eb6ad4f..682d5348 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs @@ -45,12 +45,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes /// /// Returns the node sub type if the object can have sub types otehr wise returns empty string /// - public abstract string GetNodeSubType(object context); + public abstract string GetNodeSubType(object smoObject, SmoQueryContext smoContext); /// /// Returns the status of the object assigned to node. If the object doesn't spport status returns empty string /// - public abstract string GetNodeStatus(object context); + public abstract string GetNodeStatus(object smoObject, SmoQueryContext smoContext); /// /// Returns the custom name of the object assigned to the node. If the object doesn't have custom name, returns empty string diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs index b7d8fad5..735ecffe 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -29,6 +30,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes get { return numInits.HasValue && numInits != 0; } } + public bool IsSorted + { + get + { + // SMO objects are already sorted so no need to sort them again + return this.FirstOrDefault() is SmoTreeNode; + } + } + public void BeginInit() { if (!numInits.HasValue) @@ -54,7 +64,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes { try { - DoSort(); + if (!IsSorted) + { + DoSort(); + } if (deferredChildren != null) { diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs index 045f0a76..0cdb24fa 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs @@ -17,6 +17,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { public class SmoChildFactoryBase : ChildFactory { + private IEnumerable smoProperties; public override IEnumerable ApplicableParents() { return null; @@ -230,6 +231,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel } else { + smoProperties = SmoProperties; SmoTreeNode childAsMeItem = (SmoTreeNode)child; childAsMeItem.CacheInfoFromModel(smoObj); SmoQueryContext smoContext = parent.GetContextAs(); @@ -241,8 +243,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel childAsMeItem.NodeValue = customizedName; } - childAsMeItem.NodeSubType = GetNodeSubType(context); - childAsMeItem.NodeStatus = GetNodeStatus(context); + childAsMeItem.NodeSubType = GetNodeSubType(context, smoContext); + childAsMeItem.NodeStatus = GetNodeStatus(context, smoContext); } } @@ -270,6 +272,14 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel } } + internal IEnumerable CachedSmoProperties + { + get + { + return smoProperties == null ? SmoProperties : smoProperties; + } + } + /// /// Returns true if any final validation of the object to be added passes, and false /// if validation fails. This provides a chance to filter specific items out of a list @@ -282,16 +292,31 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel return true; } - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { return string.Empty; } - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { return string.Empty; } + public static bool IsPropertySupported(string propertyName, SmoQueryContext context, NamedSmoObject smoObj, IEnumerable supportedProperties) + { + var property = supportedProperties.FirstOrDefault(x => string.Compare(x.Name, propertyName, StringComparison.InvariantCultureIgnoreCase) == 0); + if (property != null) + { + return ServerVersionHelper.IsValidFor(context.ValidFor, property.ValidFor); + } + else + { + // Return true if cannot find the proeprty, SMO still tries to get that property but adding the property to supported list can make loading the nodes faster + Logger.Write(LogLevel.Verbose, $"Smo property name {propertyName} for Smo type {smoObj.GetType()} is not added as supported properties. This can cause the performance of loading the OE nodes"); + return true; + } + } + public override string GetNodeCustomName(object smoObject, SmoQueryContext smoContext) { return string.Empty; diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs index 700f87ff..b76ce5d5 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs @@ -4,6 +4,8 @@ // using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes; +using System.Collections.Generic; namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { @@ -12,21 +14,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class DatabasesChildFactory : SmoChildFactoryBase { - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { - return DatabasesCustomNodeHelper.GetStatus(context); + return DatabasesCustomNodeHelper.GetStatus(smoObject, smoContext, CachedSmoProperties); } } internal static class DatabasesCustomNodeHelper { - internal static string GetStatus(object context) + internal static string GetStatus(object smoObject, SmoQueryContext smoContext, IEnumerable supportedProperties) { - Database db = context as Database; - if (db != null) + Database db = smoObject as Database; + if (db != null && SmoChildFactoryBase.IsPropertySupported("Status", smoContext, db, supportedProperties)) { DatabaseStatus status; - try { + try + { status = db.Status; } catch (SqlServer.Management.Common.ConnectionFailureException) diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs index 9a9cafe3..cf852806 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs @@ -12,9 +12,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class KeysChildFactory : SmoChildFactoryBase { - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return IndexCustomeNodeHelper.GetSubType(context); + return IndexCustomeNodeHelper.GetSubType(smoObject); } } @@ -23,9 +23,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class IndexesChildFactory : SmoChildFactoryBase { - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return IndexCustomeNodeHelper.GetSubType(context); + return IndexCustomeNodeHelper.GetSubType(smoObject); } public override string GetNodeCustomName(object smoObject, SmoQueryContext smoContext) @@ -39,9 +39,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class UserDefinedTableTypeKeysChildFactory : SmoChildFactoryBase { - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return IndexCustomeNodeHelper.GetSubType(context); + return IndexCustomeNodeHelper.GetSubType(smoObject); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs index 524fa6fa..64a3b453 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs @@ -12,9 +12,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class ServerLevelLoginsChildFactory : SmoChildFactoryBase { - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { - return LoginCustomNodeHelper.GetStatus(context); + return LoginCustomNodeHelper.GetStatus(smoObject); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs index 61671445..7c8ef0a3 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs @@ -18,9 +18,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel return ParameterCustomeNodeHelper.GetCustomLabel(smoObject, smoContext); } - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return ParameterCustomeNodeHelper.GetSubType(context); + return ParameterCustomeNodeHelper.GetSubType(smoObject); } } @@ -33,9 +33,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { return ParameterCustomeNodeHelper.GetCustomLabel(smoObject, smoContext); } - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return ParameterCustomeNodeHelper.GetSubType(context); + return ParameterCustomeNodeHelper.GetSubType(smoObject); } } @@ -48,9 +48,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { return ParameterCustomeNodeHelper.GetCustomLabel(smoObject, smoContext); } - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return ParameterCustomeNodeHelper.GetSubType(context); + return ParameterCustomeNodeHelper.GetSubType(smoObject); } } @@ -63,9 +63,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { return ParameterCustomeNodeHelper.GetCustomLabel(smoObject, smoContext); } - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { - return ParameterCustomeNodeHelper.GetSubType(context); + return ParameterCustomeNodeHelper.GetSubType(smoObject); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs index 08710c8e..314ae07f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs @@ -17,7 +17,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel try { Table table = smoObject as Table; - if (table != null && table.IsSystemVersioned) + if (table != null && IsPropertySupported("IsSystemVersioned", smoContext, table, CachedSmoProperties) && table.IsSystemVersioned) { return $"{table.Schema}.{table.Name} ({SR.SystemVersioned_LabelPart})"; } @@ -30,12 +30,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel return string.Empty; } - public override string GetNodeSubType(object context) + public override string GetNodeSubType(object smoObject, SmoQueryContext smoContext) { try { - Table table = context as Table; - if (table != null && table.TemporalType != TableTemporalType.None) + Table table = smoObject as Table; + if (table != null && IsPropertySupported("TemporalType", smoContext, table, CachedSmoProperties) && table.TemporalType != TableTemporalType.None) { return "Temporal"; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTriggerCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTriggerCustomNode.cs index e663ec84..48d07579 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTriggerCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTriggerCustomNode.cs @@ -12,25 +12,25 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class TriggersChildFactory : SmoChildFactoryBase { - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { - return TriggersCustomeNodeHelper.GetStatus(context); + return TriggersCustomeNodeHelper.GetStatus(smoObject); } } internal partial class ServerLevelServerTriggersChildFactory : SmoChildFactoryBase { - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { - return TriggersCustomeNodeHelper.GetStatus(context); + return TriggersCustomeNodeHelper.GetStatus(smoObject); } } internal partial class DatabaseTriggersChildFactory : SmoChildFactoryBase { - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { - return TriggersCustomeNodeHelper.GetStatus(context); + return TriggersCustomeNodeHelper.GetStatus(smoObject); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoUserCustomNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoUserCustomNode.cs index cb7593ca..9d969fd8 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoUserCustomNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoUserCustomNode.cs @@ -12,9 +12,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel /// internal partial class UsersChildFactory : SmoChildFactoryBase { - public override string GetNodeStatus(object context) + public override string GetNodeStatus(object smoObject, SmoQueryContext smoContext) { - return UserCustomeNodeHelper.GetStatus(context); + return UserCustomeNodeHelper.GetStatus(smoObject); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/ObjectExplorer/Baselines/AllSqlObjects.txt b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/ObjectExplorer/Baselines/AllSqlObjects.txt index 4a8f81a1..4ae253fd 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/ObjectExplorer/Baselines/AllSqlObjects.txt +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/ObjectExplorer/Baselines/AllSqlObjects.txt @@ -33,8 +33,8 @@ NodeType: Column Label: SickLeaveHours (smallint, not null) SubType: Status: NodeType: Column Label: CurrentFlag (Flag(bit), not null) SubType: Status: NodeType: Column Label: rowguid (uniqueidentifier, not null) SubType: Status: NodeType: Column Label: ModifiedDate (datetime, not null) SubType: Status: -NodeType: Key Label: FK_Employee_Person_BusinessEntityID SubType:ForeignKey Status: NodeType: Key Label: PK_Employee_BusinessEntityID SubType:PrimaryKey Status: +NodeType: Key Label: FK_Employee_Person_BusinessEntityID SubType:ForeignKey Status: NodeType: Constraint Label: CK_Employee_BirthDate SubType: Status: NodeType: Constraint Label: CK_Employee_Gender SubType: Status: NodeType: Constraint Label: CK_Employee_HireDate SubType: Status: @@ -156,7 +156,6 @@ NodeType: DatabaseRole Label: db_securityadmin SubType: Status: NodeType: DatabaseRole Label: public SubType: Status: NodeType: DatabaseRole Label: SalesManagers SubType: Status: NodeType: DatabaseRole Label: SalesPersons SubType: Status: -NodeType: Schema Label: dbo SubType: Status: NodeType: Schema Label: db_accessadmin SubType: Status: NodeType: Schema Label: db_backupoperator SubType: Status: NodeType: Schema Label: db_datareader SubType: Status: @@ -166,6 +165,7 @@ NodeType: Schema Label: db_denydatareader SubType: Status: NodeType: Schema Label: db_denydatawriter SubType: Status: NodeType: Schema Label: db_owner SubType: Status: NodeType: Schema Label: db_securityadmin SubType: Status: +NodeType: Schema Label: dbo SubType: Status: NodeType: Schema Label: Demo SubType: Status: NodeType: Schema Label: guest SubType: Status: NodeType: Schema Label: HumanResources SubType: Status: