/// <summary> /// Executes this batch and captures any server messages that are returned. /// </summary> /// <param name="conn">The connection to use to execute the batch</param> /// <param name="cancellationToken">Token for cancelling the execution</param> public async Task Execute(DbConnection conn, CancellationToken cancellationToken) { // Sanity check to make sure we haven't already run this batch if (HasExecuted) { throw new InvalidOperationException("Batch has already executed."); } // Notify that we've started execution if (BatchStart != null) { await BatchStart(this); } // Register the message listener to *this instance* of the batch // Note: This is being done to associate messages with batches ReliableSqlConnection sqlConn = conn as ReliableSqlConnection; if (sqlConn != null) { sqlConn.GetUnderlyingConnection().InfoMessage += ServerMessageHandler; } try { await DoExecute(conn, cancellationToken); } catch (TaskCanceledException) { // Cancellation isn't considered an error condition await SendMessage(SR.QueryServiceQueryCancelled, false); throw; } catch (Exception e) { HasError = true; await SendMessage(SR.QueryServiceQueryFailed(e.Message), true); throw; } finally { // Remove the message event handler from the connection if (sqlConn != null) { sqlConn.GetUnderlyingConnection().InfoMessage -= ServerMessageHandler; } // Mark that we have executed HasExecuted = true; executionEndTime = DateTime.Now; // Fire an event to signify that the batch has completed if (BatchCompletion != null) { await BatchCompletion(this); } } }
private DbCommand CreateCommand(DbConnection conn) { // Register the message listener to *this instance* of the batch // Note: This is being done to associate messages with batches ReliableSqlConnection sqlConn = conn as ReliableSqlConnection; DbCommand dbCommand; if (sqlConn != null) { dbCommand = sqlConn.GetUnderlyingConnection().CreateCommand(); // Add a handler for when the command completes SqlCommand sqlCommand = (SqlCommand)dbCommand; sqlCommand.StatementCompleted += StatementCompletedHandler; } else { dbCommand = conn.CreateCommand(); } // Make sure we aren't using a ReliableCommad since we do not want automatic retry Debug.Assert(!(dbCommand is ReliableSqlConnection.ReliableSqlCommand), "ReliableSqlCommand command should not be used to execute queries"); return(dbCommand); }
private RestoreDatabaseTaskDataObject CreateRestoreForNewSession(string ownerUri, string targetDatabaseName = null) { ConnectionInfo connInfo; DisasterRecoveryService.ConnectionServiceInstance.TryFindConnection( ownerUri, out connInfo); if (connInfo != null) { SqlConnection connection; DbConnection dbConnection = connInfo.AllConnections.First(); ReliableSqlConnection reliableSqlConnection = dbConnection as ReliableSqlConnection; SqlConnection sqlConnection = dbConnection as SqlConnection; if (reliableSqlConnection != null) { connection = reliableSqlConnection.GetUnderlyingConnection(); } else if (sqlConnection != null) { connection = sqlConnection; } else { Logger.Write(LogLevel.Warning, "Cannot find any sql connection for restore operation"); return(null); } Server server = new Server(new ServerConnection(connection)); RestoreDatabaseTaskDataObject restoreDataObject = new RestoreDatabaseTaskDataObject(server, targetDatabaseName); return(restoreDataObject); } return(null); }
private SmoQueryContext CreateContext(IMultiServiceProvider serviceProvider) { string exceptionMessage; ConnectionInfo connectionInfo; SqlConnection connection = null; // Get server object from connection if (!connectionService.TryFindConnection(this.connectionUri, out connectionInfo) || connectionInfo.AllConnections == null || connectionInfo.AllConnections.Count == 0) { ErrorStateMessage = string.Format(CultureInfo.CurrentCulture, SR.ServerNodeConnectionError, connectionSummary.ServerName); return(null); } //TODO: figure out how to use existing connections DbConnection dbConnection = connectionInfo.AllConnections.First(); ReliableSqlConnection reliableSqlConnection = dbConnection as ReliableSqlConnection; SqlConnection sqlConnection = dbConnection as SqlConnection; if (reliableSqlConnection != null) { connection = reliableSqlConnection.GetUnderlyingConnection(); } else if (sqlConnection != null) { connection = sqlConnection; } else { ErrorStateMessage = string.Format(CultureInfo.CurrentCulture, SR.ServerNodeConnectionError, connectionSummary.ServerName); return(null); } try { Server server = SmoWrapper.CreateServer(connection); return(new SmoQueryContext(server, serviceProvider, SmoWrapper) { Parent = server, SqlServerType = this.sqlServerType }); } catch (ConnectionFailureException cfe) { exceptionMessage = cfe.Message; } catch (Exception ex) { exceptionMessage = ex.Message; } Logger.Write(LogLevel.Error, "Exception at ServerNode.CreateContext() : " + exceptionMessage); this.ErrorStateMessage = string.Format(SR.TreeNodeError, exceptionMessage); return(null); }
public void ReliableSqlConnectionUsesAzureToken() { ConnectionDetails details = TestObjects.GetTestConnectionDetails(); details.UserName = ""; details.Password = ""; string connectionString = ConnectionService.BuildConnectionString(details); string azureAccountToken = "testAzureAccountToken"; RetryPolicy retryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); // If I create a ReliableSqlConnection using an azure account token var reliableConnection = new ReliableSqlConnection(connectionString, retryPolicy, retryPolicy, azureAccountToken); // Then the connection's azureAccountToken gets set Assert.Equal(azureAccountToken, reliableConnection.GetUnderlyingConnection().AccessToken); }
private Server CreateServerObject(ConnectionInfo connInfo) { SqlConnection connection = null; DbConnection dbConnection = connInfo.AllConnections.First(); ReliableSqlConnection reliableSqlConnection = dbConnection as ReliableSqlConnection; SqlConnection sqlConnection = dbConnection as SqlConnection; if (reliableSqlConnection != null) { connection = reliableSqlConnection.GetUnderlyingConnection(); } else if (sqlConnection != null) { connection = sqlConnection; } return(new Server(new ServerConnection(connection))); }
public static SqlConnection GetAsSqlConnection(DbConnection connection) { SqlConnection sqlConn = connection as SqlConnection; if (sqlConn == null) { // It's not actually a SqlConnection, so let's try a reliable SQL connection ReliableSqlConnection reliableConn = connection as ReliableSqlConnection; if (reliableConn == null) { // If we don't have connection we can use with SMO, just give up on using SMO return(null); } // We have a reliable connection, use the underlying connection sqlConn = reliableConn.GetUnderlyingConnection(); } return(sqlConn); }
/// <summary> /// Generates a edit-ready metadata object using SMO /// </summary> /// <param name="connection">Connection to use for getting metadata</param> /// <param name="objectName">Name of the object to return metadata for</param> /// <param name="objectType">Type of the object to return metadata for</param> /// <returns>Metadata about the object requested</returns> public TableMetadata GetObjectMetadata(DbConnection connection, string schemaName, string objectName, string objectType) { // Get a connection to the database for SMO purposes SqlConnection sqlConn = connection as SqlConnection; if (sqlConn == null) { // It's not actually a SqlConnection, so let's try a reliable SQL connection ReliableSqlConnection reliableConn = connection as ReliableSqlConnection; if (reliableConn == null) { // If we don't have connection we can use with SMO, just give up on using SMO return(null); } // We have a reliable connection, use the underlying connection sqlConn = reliableConn.GetUnderlyingConnection(); } // Connect with SMO and get the metadata for the table ServerConnection serverConnection; if (sqlConn.AccessToken == null) { serverConnection = new ServerConnection(sqlConn); } else { serverConnection = new ServerConnection(sqlConn, new AzureAccessToken(sqlConn.AccessToken)); } Server server = new Server(serverConnection); Database database = server.Databases[sqlConn.Database]; TableViewTableTypeBase smoResult; switch (objectType.ToLowerInvariant()) { case "table": Table table = string.IsNullOrEmpty(schemaName) ? new Table(database, objectName) : new Table(database, objectName, schemaName); table.Refresh(); smoResult = table; break; case "view": View view = string.IsNullOrEmpty(schemaName) ? new View(database, objectName) : new View(database, objectName, schemaName); view.Refresh(); smoResult = view; break; default: throw new ArgumentOutOfRangeException(nameof(objectType), SR.EditDataUnsupportedObjectType(objectType)); } if (smoResult == null) { throw new ArgumentOutOfRangeException(nameof(objectName), SR.EditDataObjectMetadataNotFound); } // Generate the edit column metadata List <ColumnMetadata> editColumns = new List <ColumnMetadata>(); for (int i = 0; i < smoResult.Columns.Count; i++) { Column smoColumn = smoResult.Columns[i]; // The default value may be escaped string defaultValue = smoColumn.DefaultConstraint == null ? null : FromSqlScript.UnwrapLiteral(smoColumn.DefaultConstraint.Text); ColumnMetadata column = new ColumnMetadata { DefaultValue = defaultValue, EscapedName = ToSqlScript.FormatIdentifier(smoColumn.Name), Ordinal = i }; editColumns.Add(column); } // Only tables can be memory-optimized Table smoTable = smoResult as Table; bool isMemoryOptimized = smoTable != null && smoTable.IsMemoryOptimized; // Escape the parts of the name string[] objectNameParts = { smoResult.Schema, smoResult.Name }; string escapedMultipartName = ToSqlScript.FormatMultipartIdentifier(objectNameParts); return(new TableMetadata { Columns = editColumns.ToArray(), EscapedMultipartName = escapedMultipartName, IsMemoryOptimized = isMemoryOptimized, }); }
/// <summary> /// Generates a edit-ready metadata object using SMO /// </summary> /// <param name="connection">Connection to use for getting metadata</param> /// <param name="objectNamedParts">Split and unwrapped name parts</param> /// <param name="objectType">Type of the object to return metadata for</param> /// <returns>Metadata about the object requested</returns> public EditTableMetadata GetObjectMetadata(DbConnection connection, string[] objectNamedParts, string objectType) { Validate.IsNotNull(nameof(objectNamedParts), objectNamedParts); if (objectNamedParts.Length <= 0) { throw new ArgumentNullException(nameof(objectNamedParts), SR.EditDataMetadataObjectNameRequired); } if (objectNamedParts.Length > 2) { throw new InvalidOperationException(SR.EditDataMetadataTooManyIdentifiers); } // Get a connection to the database for SMO purposes SqlConnection sqlConn = connection as SqlConnection; if (sqlConn == null) { // It's not actually a SqlConnection, so let's try a reliable SQL connection ReliableSqlConnection reliableConn = connection as ReliableSqlConnection; if (reliableConn == null) { // If we don't have connection we can use with SMO, just give up on using SMO return(null); } // We have a reliable connection, use the underlying connection sqlConn = reliableConn.GetUnderlyingConnection(); } // Connect with SMO and get the metadata for the table ServerConnection serverConnection; if (sqlConn.AccessToken == null) { serverConnection = new ServerConnection(sqlConn); } else { serverConnection = new ServerConnection(sqlConn, new AzureAccessToken(sqlConn.AccessToken)); } Server server = new Server(serverConnection); Database db = new Database(server, sqlConn.Database); TableViewTableTypeBase smoResult; switch (objectType.ToLowerInvariant()) { case "table": smoResult = objectNamedParts.Length == 1 ? new Table(db, objectNamedParts[0]) // No schema provided : new Table(db, objectNamedParts[1], objectNamedParts[0]); // Schema provided break; case "view": smoResult = objectNamedParts.Length == 1 ? new View(db, objectNamedParts[0]) // No schema provided : new View(db, objectNamedParts[1], objectNamedParts[0]); // Schema provided break; default: throw new ArgumentOutOfRangeException(nameof(objectType), SR.EditDataUnsupportedObjectType(objectType)); } // A bug in SMO makes it necessary to call refresh to attain certain properties (such as IsMemoryOptimized) smoResult.Refresh(); if (smoResult.State != SqlSmoState.Existing) { throw new ArgumentOutOfRangeException(nameof(objectNamedParts), SR.EditDataObjectNotFound); } // Generate the edit column metadata List <EditColumnMetadata> editColumns = new List <EditColumnMetadata>(); for (int i = 0; i < smoResult.Columns.Count; i++) { Column smoColumn = smoResult.Columns[i]; string defaultValue = null; try { // The default value may be escaped defaultValue = smoColumn.DefaultConstraint == null ? null : FromSqlScript.UnwrapLiteral(smoColumn.DefaultConstraint.Text); } catch (PropertyCannotBeRetrievedException) { // This exception will be thrown when the user doesn't have view definition privilege, // we can ignore it and use null as the default value; } EditColumnMetadata column = new EditColumnMetadata { DefaultValue = defaultValue, EscapedName = ToSqlScript.FormatIdentifier(smoColumn.Name), Ordinal = i, IsHierarchyId = smoColumn.DataType.SqlDataType == SqlDataType.HierarchyId, }; editColumns.Add(column); } // Only tables can be memory-optimized Table smoTable = smoResult as Table; bool isMemoryOptimized = false; // TODO: Remove IsSupported check once SMO fixes broken IsMemoryOptimized scenario (TFS #10871823) if (smoTable != null) { isMemoryOptimized = smoTable.IsSupportedProperty("IsMemoryOptimized") && smoTable.IsMemoryOptimized; } // Escape the parts of the name string[] objectNameParts = { smoResult.Schema, smoResult.Name }; string escapedMultipartName = ToSqlScript.FormatMultipartIdentifier(objectNameParts); return(new EditTableMetadata { Columns = editColumns.ToArray(), EscapedMultipartName = escapedMultipartName, IsMemoryOptimized = isMemoryOptimized }); }
/// <summary> /// Executes this batch and captures any server messages that are returned. /// </summary> /// <param name="conn">The connection to use to execute the batch</param> /// <param name="cancellationToken">Token for cancelling the execution</param> public async Task Execute(DbConnection conn, CancellationToken cancellationToken) { // Sanity check to make sure we haven't already run this batch if (HasExecuted) { throw new InvalidOperationException("Batch has already executed."); } // Notify that we've started execution if (BatchStart != null) { await BatchStart(this); } try { // Register the message listener to *this instance* of the batch // Note: This is being done to associate messages with batches ReliableSqlConnection sqlConn = conn as ReliableSqlConnection; DbCommand command; if (sqlConn != null) { // Register the message listener to *this instance* of the batch // Note: This is being done to associate messages with batches sqlConn.GetUnderlyingConnection().InfoMessage += StoreDbMessage; command = sqlConn.GetUnderlyingConnection().CreateCommand(); // Add a handler for when the command completes SqlCommand sqlCommand = (SqlCommand)command; sqlCommand.StatementCompleted += StatementCompletedHandler; } else { command = conn.CreateCommand(); } // Make sure we aren't using a ReliableCommad since we do not want automatic retry Debug.Assert(!(command is ReliableSqlConnection.ReliableSqlCommand), "ReliableSqlCommand command should not be used to execute queries"); // Create a command that we'll use for executing the query using (command) { command.CommandText = BatchText; command.CommandType = CommandType.Text; command.CommandTimeout = 0; executionStartTime = DateTime.Now; // Execute the command to get back a reader using (DbDataReader reader = await command.ExecuteReaderAsync(cancellationToken)) { int resultSetOrdinal = 0; do { // Skip this result set if there aren't any rows (ie, UPDATE/DELETE/etc queries) if (!reader.HasRows && reader.FieldCount == 0) { continue; } // This resultset has results (ie, SELECT/etc queries) ResultSet resultSet = new ResultSet(reader, resultSetOrdinal, Id, outputFileFactory); resultSet.ResultCompletion += ResultSetCompletion; // Add the result set to the results of the query lock (resultSets) { resultSets.Add(resultSet); resultSetOrdinal++; } // Read until we hit the end of the result set await resultSet.ReadResultToEnd(cancellationToken).ConfigureAwait(false); } while (await reader.NextResultAsync(cancellationToken)); // If there were no messages, for whatever reason (NO COUNT set, messages // were emitted, records returned), output a "successful" message if (resultMessages.Count == 0) { resultMessages.Add(new ResultMessage(SR.QueryServiceCompletedSuccessfully)); } } } } catch (DbException dbe) { HasError = true; UnwrapDbException(dbe); } catch (TaskCanceledException) { resultMessages.Add(new ResultMessage(SR.QueryServiceQueryCancelled)); throw; } catch (Exception e) { HasError = true; resultMessages.Add(new ResultMessage(SR.QueryServiceQueryFailed(e.Message))); throw; } finally { // Remove the message event handler from the connection ReliableSqlConnection sqlConn = conn as ReliableSqlConnection; if (sqlConn != null) { sqlConn.GetUnderlyingConnection().InfoMessage -= StoreDbMessage; } // Mark that we have executed HasExecuted = true; executionEndTime = DateTime.Now; // Fire an event to signify that the batch has completed if (BatchCompletion != null) { await BatchCompletion(this); } } }
/// <summary> /// Executes this query asynchronously and collects all result sets /// </summary> private async Task ExecuteInternal() { ReliableSqlConnection sqlConn = null; try { // Mark that we've internally executed hasExecuteBeenCalled = true; // Don't actually execute if there aren't any batches to execute if (Batches.Length == 0) { if (BatchMessageSent != null) { await BatchMessageSent(new ResultMessage(SR.QueryServiceCompletedSuccessfully, false, null)); } if (QueryCompleted != null) { await QueryCompleted(this); } return; } // Locate and setup the connection DbConnection queryConnection = await ConnectionService.Instance.GetOrOpenConnection(editorConnection.OwnerUri, ConnectionType.Query); sqlConn = queryConnection as ReliableSqlConnection; if (sqlConn != null) { // Subscribe to database informational messages sqlConn.GetUnderlyingConnection().FireInfoMessageEventOnUserErrors = true; sqlConn.GetUnderlyingConnection().InfoMessage += OnInfoMessage; } // Execute beforeBatches synchronously, before the user defined batches foreach (Batch b in BeforeBatches) { await b.Execute(queryConnection, cancellationSource.Token); } // We need these to execute synchronously, otherwise the user will be very unhappy foreach (Batch b in Batches) { // Add completion callbacks b.BatchStart += BatchStarted; b.BatchCompletion += BatchCompleted; b.BatchMessageSent += BatchMessageSent; b.ResultSetCompletion += ResultSetCompleted; await b.Execute(queryConnection, cancellationSource.Token); } // Execute afterBatches synchronously, after the user defined batches foreach (Batch b in AfterBatches) { await b.Execute(queryConnection, cancellationSource.Token); } // Call the query execution callback if (QueryCompleted != null) { await QueryCompleted(this); } } catch (Exception e) { // Call the query failure callback if (QueryFailed != null) { await QueryFailed(this, e); } } finally { // Remove the message handler from the connection if (sqlConn != null) { // Subscribe to database informational messages sqlConn.GetUnderlyingConnection().InfoMessage -= OnInfoMessage; } // If any message notified us we had changed databases, then we must let the connection service know if (newDatabaseName != null) { ConnectionService.Instance.ChangeConnectionDatabaseContext(editorConnection.OwnerUri, newDatabaseName); } foreach (Batch b in Batches) { if (b.HasError) { ConnectionService.EnsureConnectionIsOpen(sqlConn); break; } } } }
/// <summary> /// Executes this query asynchronously and collects all result sets /// </summary> private async Task ExecuteInternal() { // Mark that we've internally executed hasExecuteBeenCalled = true; // Don't actually execute if there aren't any batches to execute if (Batches.Length == 0) { return; } // Open up a connection for querying the database string connectionString = ConnectionService.BuildConnectionString(editorConnection.ConnectionDetails); // TODO: Don't create a new connection every time, see TFS #834978 using (DbConnection conn = editorConnection.Factory.CreateSqlConnection(connectionString)) { try { await conn.OpenAsync(); } catch (Exception exception) { this.HasExecuted = true; if (QueryConnectionException != null) { await QueryConnectionException(exception.Message); } return; } ReliableSqlConnection sqlConn = conn as ReliableSqlConnection; if (sqlConn != null) { // Subscribe to database informational messages sqlConn.GetUnderlyingConnection().InfoMessage += OnInfoMessage; } try { // We need these to execute synchronously, otherwise the user will be very unhappy foreach (Batch b in Batches) { b.BatchStart += BatchStarted; b.BatchCompletion += BatchCompleted; b.ResultSetCompletion += ResultSetCompleted; await b.Execute(conn, cancellationSource.Token); } // Call the query execution callback if (QueryCompleted != null) { await QueryCompleted(this); } } catch (Exception) { // Call the query failure callback if (QueryFailed != null) { await QueryFailed(this); } } finally { if (sqlConn != null) { // Subscribe to database informational messages sqlConn.GetUnderlyingConnection().InfoMessage -= OnInfoMessage; } } // TODO: Close connection after eliminating using statement for above TODO } }
private async Task ExecuteOnce(DbConnection conn, CancellationToken cancellationToken) { // Make sure we haven't cancelled yet cancellationToken.ThrowIfCancellationRequested(); // Register the message listener to *this instance* of the batch // Note: This is being done to associate messages with batches ReliableSqlConnection sqlConn = conn as ReliableSqlConnection; DbCommand dbCommand; if (sqlConn != null) { // Register the message listener to *this instance* of the batch // Note: This is being done to associate messages with batches sqlConn.GetUnderlyingConnection().InfoMessage += ServerMessageHandler; dbCommand = sqlConn.GetUnderlyingConnection().CreateCommand(); // Add a handler for when the command completes SqlCommand sqlCommand = (SqlCommand)dbCommand; sqlCommand.StatementCompleted += StatementCompletedHandler; } else { dbCommand = conn.CreateCommand(); } // Make sure we aren't using a ReliableCommad since we do not want automatic retry Debug.Assert(!(dbCommand is ReliableSqlConnection.ReliableSqlCommand), "ReliableSqlCommand command should not be used to execute queries"); // Create a command that we'll use for executing the query using (dbCommand) { // Make sure that we cancel the command if the cancellation token is cancelled cancellationToken.Register(() => dbCommand?.Cancel()); // Setup the command for executing the batch dbCommand.CommandText = BatchText; dbCommand.CommandType = CommandType.Text; dbCommand.CommandTimeout = 0; executionStartTime = DateTime.Now; // Execute the command to get back a reader using (DbDataReader reader = await dbCommand.ExecuteReaderAsync(cancellationToken)) { int resultSetOrdinal = 0; do { // Verify that the cancellation token hasn't benn cancelled cancellationToken.ThrowIfCancellationRequested(); // Skip this result set if there aren't any rows (ie, UPDATE/DELETE/etc queries) if (!reader.HasRows && reader.FieldCount == 0) { continue; } // This resultset has results (ie, SELECT/etc queries) ResultSet resultSet = new ResultSet(resultSetOrdinal, Id, outputFileFactory); resultSet.ResultCompletion += ResultSetCompletion; // Add the result set to the results of the query lock (resultSets) { resultSets.Add(resultSet); resultSetOrdinal++; } // Read until we hit the end of the result set await resultSet.ReadResultToEnd(reader, cancellationToken); } while (await reader.NextResultAsync(cancellationToken)); // If there were no messages, for whatever reason (NO COUNT set, messages // were emitted, records returned), output a "successful" message if (!messagesSent) { await SendMessage(SR.QueryServiceCompletedSuccessfully, false); } } } }
/// <summary> /// Generates a edit-ready metadata object using SMO /// </summary> /// <param name="connection">Connection to use for getting metadata</param> /// <param name="objectNamedParts">Split and unwrapped name parts</param> /// <param name="objectType">Type of the object to return metadata for</param> /// <returns>Metadata about the object requested</returns> public EditTableMetadata GetObjectMetadata(DbConnection connection, string[] objectNamedParts, string objectType) { Validate.IsNotNull(nameof(objectNamedParts), objectNamedParts); if (objectNamedParts.Length <= 0) { throw new ArgumentNullException(nameof(objectNamedParts), SR.EditDataMetadataObjectNameRequired); } if (objectNamedParts.Length > 2) { throw new InvalidOperationException(SR.EditDataMetadataTooManyIdentifiers); } // Get a connection to the database for SMO purposes SqlConnection sqlConn = connection as SqlConnection; if (sqlConn == null) { // It's not actually a SqlConnection, so let's try a reliable SQL connection ReliableSqlConnection reliableConn = connection as ReliableSqlConnection; if (reliableConn == null) { // If we don't have connection we can use with SMO, just give up on using SMO return(null); } // We have a reliable connection, use the underlying connection sqlConn = reliableConn.GetUnderlyingConnection(); } // Connect with SMO and get the metadata for the table Server server = new Server(new ServerConnection(sqlConn)); Database db = new Database(server, sqlConn.Database); TableViewTableTypeBase smoResult; switch (objectType.ToLowerInvariant()) { case "table": smoResult = objectNamedParts.Length == 1 ? new Table(db, objectNamedParts[0]) // No schema provided : new Table(db, objectNamedParts[1], objectNamedParts[0]); // Schema provided break; case "view": smoResult = objectNamedParts.Length == 1 ? new View(db, objectNamedParts[0]) // No schema provided : new View(db, objectNamedParts[1], objectNamedParts[0]); // Schema provided break; default: throw new ArgumentOutOfRangeException(nameof(objectType), SR.EditDataUnsupportedObjectType(objectType)); } // A bug in SMO makes it necessary to call refresh to attain certain properties (such as IsMemoryOptimized) smoResult.Refresh(); if (smoResult.State != SqlSmoState.Existing) { throw new ArgumentOutOfRangeException(nameof(objectNamedParts), SR.EditDataObjectNotFound); } // Generate the edit column metadata List <EditColumnMetadata> editColumns = new List <EditColumnMetadata>(); for (int i = 0; i < smoResult.Columns.Count; i++) { Column smoColumn = smoResult.Columns[i]; // The default value may be escaped string defaultValue = smoColumn.DefaultConstraint == null ? null : SqlScriptFormatter.UnwrapLiteral(smoColumn.DefaultConstraint.Text); EditColumnMetadata column = new EditColumnMetadata { DefaultValue = defaultValue, EscapedName = SqlScriptFormatter.FormatIdentifier(smoColumn.Name), Ordinal = i, }; editColumns.Add(column); } // Only tables can be memory-optimized Table smoTable = smoResult as Table; bool isMemoryOptimized = smoTable != null && smoTable.IsMemoryOptimized; // Escape the parts of the name string[] objectNameParts = { smoResult.Schema, smoResult.Name }; string escapedMultipartName = SqlScriptFormatter.FormatMultipartIdentifier(objectNameParts); return(new EditTableMetadata { Columns = editColumns.ToArray(), EscapedMultipartName = escapedMultipartName, IsMemoryOptimized = isMemoryOptimized, }); }