当并非所有数据库都有用户用于连接到服务器时,如何使用 SMO 列出 SQL Azure 服务器上的数据库?

How do I list databases on SQL Azure server using SMO when not all databases have the user used to connect to the server?

如果服务器上的一个数据库没有我用来创建 SMO 服务器连接的 SQL 用户,SMO 的 Server.Databases 将抛出异常。

如果使用本地 SQL 2017 实例,我不会发生同样的错误。

例如:

我有一个名为 'myazuresqlserver.database.windows.net'

的 SQL Azure 服务器
  1. 在主服务器上创建登录名

    使用密码创建登录名 testlogin = 'ThisIsMySecretPassword'

  2. 创建 2 个数据库,DB1 和 DB2。

  3. 在 DB1 中创建用户 'testuser' 但 NOT DB2:

    创建用户 testuser 用于登录 testlogin

然后,使用 C# 和 SMO,我无法使用 testlogin 登录凭据获取该服务器的数据库列表 - 出现异常。

static void Main(string[] args)
{
    string[] names = GetDatabaseNames("myazuresqlserver.database.windows.net");
}

public static string[] GetDatabaseNames(string serverName)
{       
    ServerConnection connection = new ServerConnection(serverName, "testuser", "ThisIsMySecretPassword");
    var server = new Server(connection);
    return (from Database database in server.Databases
        where !database.IsSystemObject && !database.IsDatabaseSnapshot
        select database.Name
       ).ToArray();
}

例外情况是:

SqlException: The server principal "testlogin" is not able to access the database "DB2" under the current security context.
Cannot open database "DB2" requested by the login. The login failed. Login failed for user 'testlogin'.

我原以为不会抛出异常,而是 Server.Databases 只包含提供的凭据有效的数据库 - 这似乎是本地 SQL 2017 实例的行为.

我遇到了同样的问题。就好像试图查看 Server.Databases 会导致枚举发生,并且在这样做时正在查看数据库属性 - 用户可能无权查询的属性。立即抛出异常。

我最终使用了一种不同的技术来获取数据库列表。我只是触发了一个 sql 查询:

SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb');

要使上述查询生效,用户必须具有访问 master 数据库的权限。这是我的代码块:

Dim Server As Server = New Server(New ServerConnection("myserver.server.net", "testlogin", "password"))
Dim databaseList As New DataTable
databaseList.Columns.Add("Name")

If Server.Edition = "SQL Azure" Then
    Dim SQLReader As SqlClient.SqlDataReader = Nothing
    Try
        SQLReader = Server.ConnectionContext.ExecuteReader("SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb');")

        Do While SQLReader.Read = True
            databaseList.Rows.Add(Manager.Database.Sanitise(SQLReader, "name").ToString)
        Loop

        SQLReader.Close()
    Catch ex As Exception
        MsgBox(ex.Message)
    Finally
        If Not SQLReader Is Nothing Then
            SQLReader.Close()
        End If
    End Try
End If