diff --git a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs
index f5d9e55f..8d837b3b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs
@@ -30,6 +30,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata.Contracts
public string Schema { get; set; }
public string Name { get; set; }
+
+ public string ParentName { get; set; }
+
+ public string ParentTypeName { get; set; }
public string Urn { get; set; }
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs
index 9f71e840..7c2e076c 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs
@@ -4,6 +4,7 @@
//
using System.Globalization;
+using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
@@ -56,13 +57,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
SmoObject = smoObject;
NodeValue = smoObject.Name;
- ScriptSchemaObjectBase schemaBasecObject = smoObject as ScriptSchemaObjectBase;
+ ScriptSchemaObjectBase schemaBaseObject = smoObject as ScriptSchemaObjectBase;
ObjectMetadata = new Metadata.Contracts.ObjectMetadata();
ObjectMetadata.Name = smoObject.Name;
try
{
- if(smoObject.Urn != null)
+ if (smoObject.Urn != null)
{
ObjectMetadata.MetadataTypeName = smoObject.Urn.Type;
}
@@ -72,16 +73,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
//Ignore the exception, sometimes the urn returns exception and I' not sure why
}
- if (schemaBasecObject != null)
+ if (schemaBaseObject != null)
{
- ObjectMetadata.Schema = schemaBasecObject.Schema;
+ ObjectMetadata.Schema = schemaBaseObject.Schema;
if (!string.IsNullOrEmpty(ObjectMetadata.Schema))
{
NodeValue = $"{ObjectMetadata.Schema}.{smoObject.Name}";
}
}
+ else
+ {
+ // Try to read the schema from the parent object
+ var parent = smoObject?.ParentCollection?.ParentInstance as ScriptSchemaObjectBase;
+ if (parent != null)
+ {
+ ObjectMetadata.Schema = parent.Schema;
+ ObjectMetadata.ParentName = parent.Name;
+ ObjectMetadata.ParentTypeName = parent.Urn.Type;
+ }
+ }
}
-
+
public virtual NamedSmoObject GetParentSmoObject()
{
if (SmoObject != null)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs
index 6ecea44c..49dad72c 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs
@@ -4,7 +4,6 @@
//
using System;
-using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
{
@@ -52,13 +51,28 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
///
public string Name { get; set; }
+ ///
+ /// Gets or sets the parent object name
+ ///
+ public string ParentName { get; set; }
+
+ ///
+ /// Gets or sets the parent object type name, such as Table, View, etc.
+ ///
+ public string ParentTypeName { get; set; }
+
public override string ToString()
{
- string objectName = string.IsNullOrEmpty(this.Schema)
- ? this.Name
- : this.Schema + "." + this.Name;
-
- return objectName;
+ string objectName = string.Empty;
+ if (!string.IsNullOrEmpty(this.Schema))
+ {
+ objectName += this.Schema + ".";
+ }
+ if (!string.IsNullOrEmpty(this.ParentName))
+ {
+ objectName += this.ParentName + ".";
+ }
+ return objectName + this.Name;
}
public override int GetHashCode()
@@ -66,6 +80,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
return
StringComparer.OrdinalIgnoreCase.GetHashCode(this.Type ?? string.Empty) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(this.Schema ?? string.Empty) ^
+ StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParentName ?? string.Empty) ^
+ StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParentTypeName ?? string.Empty) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(this.Name ?? string.Empty);
}
@@ -87,6 +103,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
return
string.Equals(this.Type, other.Type, StringComparison.OrdinalIgnoreCase) &&
string.Equals(this.Schema, other.Schema, StringComparison.OrdinalIgnoreCase) &&
+ string.Equals(this.ParentName, other.ParentName, StringComparison.OrdinalIgnoreCase) &&
+ string.Equals(this.ParentTypeName, other.ParentTypeName, StringComparison.OrdinalIgnoreCase) &&
+ string.Equals(this.ParentTypeName, other.ParentTypeName, StringComparison.OrdinalIgnoreCase) &&
string.Equals(this.Name, other.Name, StringComparison.OrdinalIgnoreCase);
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs
index df13e3e1..7e4f6197 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.SqlScriptPublish;
@@ -100,15 +101,35 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
Validate.IsNotNullOrWhitespaceString("scriptingObject.Type", scriptingObject.Type);
// Leaving the server name blank will automatically match whatever the server SMO is running against.
- string urn = string.Format(
- "Server[@Name='{0}']/Database[@Name='{1}']/{2}[@Name='{3}' {4}]",
- server.ToUpper(),
- Urn.EscapeString(database),
- scriptingObject.Type,
- Urn.EscapeString(scriptingObject.Name),
- scriptingObject.Schema != null ? string.Format("and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema)) : string.Empty);
+ StringBuilder urnBuilder = new StringBuilder();
+ urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper());
+ urnBuilder.AppendFormat("Database[@Name='{0}']/", Urn.EscapeString(database));
- return new Urn(urn);
+ bool hasParentObject = !string.IsNullOrWhiteSpace(scriptingObject.ParentName)
+ && !string.IsNullOrWhiteSpace(scriptingObject.ParentTypeName);
+ if (hasParentObject)
+ {
+ urnBuilder.AppendFormat("{0}[@Name='{1}'", scriptingObject.ParentTypeName, Urn.EscapeString(scriptingObject.ParentName));
+ if (!string.IsNullOrWhiteSpace(scriptingObject.Schema))
+ {
+ urnBuilder.AppendFormat(" and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema));
+ }
+ urnBuilder.Append("]/");
+ }
+
+ urnBuilder.AppendFormat("{0}[@Name='{1}'", scriptingObject.Type, Urn.EscapeString(scriptingObject.Name));
+
+ // add schema to object only if there is no parent object specified
+ // the parent object field is only set for objects that don't have schema themselves
+ // so if parent is not null then the schema filter will already be set that part of the urn above
+ if (!string.IsNullOrWhiteSpace(scriptingObject.Schema) && !hasParentObject)
+ {
+ urnBuilder.AppendFormat(" and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema));
+ }
+
+ urnBuilder.Append("]");
+
+ return new Urn(urnBuilder.ToString());
}
///