// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Globalization; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.Extensibility; using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes; namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { /// /// Context object containing key properties needed to query for SMO objects /// public class SmoQueryContext { private Server server; private Database database; private SmoObjectBase parent; private SmoWrapper smoWrapper; private ValidForFlag validFor = 0; /// /// Creates a context object with a server to use as the basis for any queries /// /// public SmoQueryContext(Server server, IMultiServiceProvider serviceProvider) : this(server, serviceProvider, null) { } internal SmoQueryContext(Server server, IMultiServiceProvider serviceProvider, SmoWrapper serverManager) { this.server = server; ServiceProvider = serviceProvider; this.smoWrapper = serverManager ?? new SmoWrapper(); } /// /// The server type /// public SqlServerType SqlServerType { get; set; } /// /// The server SMO will query against /// public Server Server { get { return GetObjectWithOpenedConnection(server); } } /// /// Optional Database context object to query against /// public Database Database { get { return GetObjectWithOpenedConnection(database); } set { database = value; } } /// /// Parent of a give node to use for queries /// public SmoObjectBase Parent { get { return GetObjectWithOpenedConnection(parent); } set { parent = value; } } /// /// A query loader that can be used to find objects /// for specific SMO types /// public IMultiServiceProvider ServiceProvider { get; private set; } /// /// Helper method to cast a parent to a specific type /// /// /// public T ParentAs() where T : TreeNode { return Parent as T; } /// /// Gets the if available, by looking it up /// from the /// /// /// /// Thrown if the is not set or the /// isn't available from that provider /// public ObjectExplorerService GetObjectExplorerService() { if (ServiceProvider == null) { throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet); } ObjectExplorerService service = ServiceProvider.GetService(); if (service == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SqlTools.Hosting.SR.ServiceNotFound, nameof(ObjectExplorerService))); } return service; } /// /// Copies the context for use by another node /// /// New Parent to set /// new with all fields except the same public SmoQueryContext CopyWithParent(SmoObjectBase parent) { SmoQueryContext context = new SmoQueryContext(this.Server, this.ServiceProvider, this.smoWrapper) { database = this.Database, Parent = parent, SqlServerType = this.SqlServerType, ValidFor = ValidFor }; return context; } /// /// Indicates which platforms the server and database is valid for /// public ValidForFlag ValidFor { get { if(validFor == 0) { validFor = ServerVersionHelper.GetValidForFlag(SqlServerType, Database); } return validFor; } set { validFor = value; } } private T GetObjectWithOpenedConnection(T smoObj) where T : SmoObjectBase { if (smoObj != null) { EnsureConnectionOpen(smoObj); } return smoObj; } /// /// Ensures the server objects connection context is open. This is used by all child objects, and /// the only way to easily access is via the server object. This should be called during access of /// any of the object properties /// public void EnsureConnectionOpen(SmoObjectBase smoObj) { if (!smoWrapper.IsConnectionOpen(smoObj)) { // We have a closed server connection. Reopen this // Note: not currently catching connection exceptions. Expect this to bubble // up to calling methods and be logged there as this would be happening there in any case smoWrapper.OpenConnection(smoObj); } } } }