无法使用SMO在SQL Azure数据库中创建表

时间:2011-04-27 00:59:16

标签: c# smo azure-sql-database

由于SQL Azure不支持USE [dbname],我试图通过在连接字符串中指定数据库名称然后执行CREATE TABLE...脚本来连接到我的SQL Azure数据库。但是,这会因System.Data.SqlClient.SqlException “在数据库'master'中拒绝CREATE TABLE权限而失败。”我在这里做错了,它试图对master执行此语句?

以下是C#代码示例:

string connectionString = @"Data Source=tcp:MYSERVER.database.windows.net;Initial Catalog=MYDATABASE;Integrated Security=False;User ID=USER@MYSERVER;Password=PWD;Connect Timeout=60;Encrypt=True;TrustServerCertificate=True";

using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); ServerConnection serverConnection = new ServerConnection(connection); Server server = new Server(serverConnection); server.ConnectionContext.ExecuteNonQuery("CREATE TABLE New (NewId int)"); }

3 个答案:

答案 0 :(得分:8)

事实证明我的代码存在多个问题。在SQL Azure中,SMO仍然很古怪。所以,发布我的调查结果,以防有人正在经历同样的艰难道路。

  1. 每次获得如下数据库对象时,SMO都会在后台切换默认数据库:
    
    Database database = server.Databases[databaseName]
    
    初始目录成为Master,您可以在 server.ConnectionContext.ConnectionString (“普通”SQL不执行此操作)中更改的连接字符串中看到它。对此的解决方案是每次将数据库切换到Master时打开一个新连接(并关闭旧连接),因为一旦建立连接就无法更改数据库名称(显然,只有SQL Azure才能这样做)。
  2. 打开初始化ServerConnection和Server的连接有时会与第一个问题一起失败。这将给出一个模糊的错误消息,指出登录失败,提供guid和时间戳要求联系客户支持。废话。解决此问题的方法是打开连接,让ServerConnection在Server对象初始化期间打开它:
  3. 最后,SQL Azure在Server对象上不喜欢Alter()。删除了所有Alter的。
  4. 所以最终的代码片段看起来像这样:

    
           string connectionString = "Server=tcp:XXXXX.database.windows.net;Database=XXXXXX;User ID=XXXXXX;Password=XXXXX;Trusted_Connection=False;Encrypt=True;trustservercertificate=true";
           SqlConnection connection = new SqlConnection(connectionString);
           // do not explicitly open connection, it will be opened when Server is initialized
           // connection.Open();
    
           ServerConnection serverConnection = new ServerConnection(connection);
           Server server = new Server(serverConnection);
    
           // after this line, the default database will be switched to Master
           Database database = server.Databases["MyDatabase"];
    
           // you can still use this database object and server connection to 
           // do certain things against this database, like adding database roles 
           // and users      
           DatabaseRole role = new DatabaseRole(database, "NewRole");
           role.Create();
    
           // if you want to execute a script against this database, you have to open 
           // another connection and re-initiliaze the server object
           server.ConnectionContext.Disconnect();
    
           connection = new SqlConnection(connectionString);
           serverConnection = new ServerConnection(connection);
           server = new Server(serverConnection);
           server.ConnectionContext.ExecuteNonQuery("CREATE TABLE New (NewId int)");
    

    如果有人感兴趣,这里是第2点的模糊例外:

    
    Microsoft.SqlServer.Management.Common.ConnectionFailureException was unhandled
      Message=Failed to connect to server .
      Source=Microsoft.SqlServer.Smo
      StackTrace:
           at Microsoft.SqlServer.Management.Smo.DatabaseCollection.get_Item(String name)
           InnerException: System.Data.SqlClient.SqlException
           Message=Login failed for user 'XXXXXXXX'.
           This session has been assigned a tracing ID of 'XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'.  Provide this tracing ID to customer support when you need assistance.
           Source=.Net SqlClient Data Provider
           ErrorCode=-2146232060
           Class=14
           LineNumber=65536
           Number=18456
           Procedure=""
           Server=tcp:XXXXXXXX.database.windows.net
           State=1
           StackTrace:
                at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
                at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
                at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
                at System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
                at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, SqlConnection owningObject)
                at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout)
                at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
                at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
                at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
                at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options)
                at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
                at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
                at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
                at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
                at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
                at System.Data.SqlClient.SqlConnection.Open()
                at Microsoft.SqlServer.Management.Common.ConnectionManager.InternalConnect(WindowsIdentity impersonatedIdentity)
                at Microsoft.SqlServer.Management.Common.ConnectionManager.Connect()
    

答案 1 :(得分:0)

只是一个疯狂的猜测,基于一个恰好适合我的连接字符串。

您是否尝试过使用

  

数据库= MYDATABASE

取代

  

初始目录= MYDATABASE

连接字符串中的

答案 2 :(得分:0)

还有一件事有助于我 - 应该为每个操作断开ServerConnection。

using (var connection = new SqlConnection(parameters.ConnectionStringToMasterDatabase))
            {
                var serverConnection = new ServerConnection(connection);
                try
                {
                    var server = new Server(serverConnection);
                    // do something
                }
                finally
                {
                    serverConnection.Disconnect();
                }
            }
using (var connection = new SqlConnection(parameters.ConnectionStringToMasterDatabase))
            {
                var serverConnection = new ServerConnection(connection);
                try
                {
                    var server = new Server(serverConnection);
                    // do something else
                }
                finally
                {
                    serverConnection.Disconnect();
                }
            }