繁体   English   中英

使用或处置 SqlConnection 不起作用,但 Close 可以吗?

[英]Using or Dispose of SqlConnection not working, but Close does?

我已经阅读了很多关于为什么你应该优先using语句而不是手动执行.Open()然后.Close()和最后.Dispose()的文章。

当我最初编写代码时,我有这样的事情:

private static void doIt(string strConnectionString, string strUsername)
{
    SqlConnection conn = new SqlConnection(strConnectionString);
    try
    {
        conn.Open();
        string strSqlCommandText = $"CREATE USER {strUsername} for LOGIN {strUsername} WITH DEFAULT SCHEMA = [dbo];";
        SqlCommand sqlCommand = new SqlCommand(strSqlCommandText, conn);
        var sqlNonReader = sqlCommand.ExecuteNonQuery();
        if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex.Message}");
    }
    finally
    {
        conn.Close();
        conn.Dispose();
    }
}

这行得通……没问题。 但只有一次。

所以,如果我做这样的事情:

private static void doItLots(string strConnectionString, string strUsername)
{
    for(int i=0; i<10; i++)
    {
        doIt(strConnectionString, $"{strUsername}_{i}");
    }
}

它在i=0时第一次工作,但任何后续迭代都失败, Cannot open database "myDbName" requested by the login. The login failed. Cannot open database "myDbName" requested by the login. The login failed.

但是,如果我返回 go 并注释掉conn.Dispose(); 行,那么它在所有迭代中都可以正常工作。

问题很简单,如果我想在方法之外执行.Dispose()部分,那么我不得不传递SqlConnection object 而不是简单地传递凭据,这可能会使我的代码不那么可移植,然后我需要保持连接的时间更长。 我一直认为您想快速打开和关闭连接,但显然我误解了.Dispose()命令的工作方式。

正如我在一开始所说的那样,我也尝试过这样using ......

private static void doIt(string strConnectionString, string strUsername)
{
    using (SqlConnection conn = new SqlConnection(strConnectionString))
    {
        try
        {
            conn.Open();
            string strSqlCommandText = $"CREATE USER {strUsername} for LOGIN {strUsername} WITH DEFAULT SCHEMA = [dbo];";
            SqlCommand sqlCommand = new SqlCommand(strSqlCommandText, conn);
            var sqlNonReader = sqlCommand.ExecuteNonQuery();
            if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
        finally
        {
            conn.Close();
        }
    }
}

这与手动调用.Dispose()的初始代码完全相同。

在这里的任何帮助将不胜感激。 我很想转换为using语句,但无法弄清楚如何以这种方式编写可重用的方法......

更新:

我已经缩小了一点。 问题不在于迭代或一遍又一遍地调用。 但我仍然遇到访问错误。 这是代码:

        string strConnectionString = $@"Data Source={StrSqlServerDataSource};Initial Catalog={StrDatabaseName};User id={StrSqlServerMasterUser};Password={StrSqlServerMasterPassword}";

        using (SqlConnection connUserDb = new SqlConnection(strConnectionString))
        {
            try
            {
                Utility.Notify($"Connection State: {connUserDb.State.ToString()}"); // Responds as 'Closed'
                connUserDb.Open(); // <-- throws error
                Utility.Notify($"Connection State: {connUserDb.State.ToString()}");

                Utility.Notify($"MSSQL Connection Open... Adding User '{strUsername}' to Database: '{strDatabaseName}'");

                string sqlCommandText =
                    //$@"USE {StrDatabaseName}; " +
                    $@"CREATE USER [{strUsername}] FOR LOGIN [{strUsername}] WITH DEFAULT_SCHEMA = [dbo]; " +
                    $@"ALTER ROLE [db_datareader] ADD MEMBER [{strUsername}]; " +
                    $@"ALTER ROLE [db_datawriter] ADD MEMBER [{strUsername}]; " +
                    $@"ALTER ROLE [db_ddladmin] ADD MEMBER [{strUsername}]; ";
                using (SqlCommand sqlCommand = new SqlCommand(sqlCommandText, connUserDb))
                {
                    var sqlNonReader = sqlCommand.ExecuteNonQuery();
                    if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername} ({sqlNonReader})");
                }

                result = true;
            }
            catch (Exception ex)
            {
                Utility.Notify($"Creating User and Updating Roles Failed: {ex.Message}", Priority.High);
            }
            finally
            {
                connUserDb.Close();
                Utility.Notify($"MSSQL Connection Closed");
            }
        }
        return result;
    }

我在这里遇到的错误是: Cannot open database requested by the login. The login failed. Cannot open database requested by the login. The login failed.

我得到的一个线索是,在此之前,我运行的是相同的代码,但有两个更改:

1) 取消注释sqlCommandText中的USE语句 2) 改为连接到Master数据库

当我这样做时,它也不起作用,而是出现此错误: The server principal is not able to access the database under the current security context.

如果我将 go 放入 SSMS 并查看它们被列为db_owner的 MasterUser,我可以执行我想要的任何活动,包括运行上面代码中包含的命令。

根据此处的建议,我重写了所有代码以使用单个连接。 在遇到“服务器主体”错误后,我又添加了一个连接以尝试直接连接到该数据库而不是master

更新 2:

这是另一个 plot 扭...

这可以在我的本地计算机上正常工作(现在)。 但是,从针对运行 MSSQL 的 Amazon Web 服务 (AWS) 关系数据库服务器 (RDS) 的 Azure Web 作业运行时,不能(总是)工作。

我明天必须审核 git 提交,但截至今天下午 5 点,它在本地和 Azure 上都有效。 上次更新后,我能够测试本地并让它工作,但是当在 Azure Webjob 上运行时,它如上所述失败。

SqlConnection 实现 IDisposable。 您不调用 dispose 或 close。

try{
 using (SqlConnection conn = new SqlConnection(strConnectionString))
    {

            conn.Open();
            string strSqlCommandText = $"CREATE USER {strUsername} for LOGIN {strUsername} WITH DEFAULT SCHEMA = [dbo];";
            SqlCommand sqlCommand = new SqlCommand(strSqlCommandText, conn);
            var sqlNonReader = sqlCommand.ExecuteNonQuery();
            if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername}");

    }}
catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM