【问题标题】:Hitting "COM object that has been separated from its underlying RCW cannot be used" error命中“无法使用已与其基础 RCW 分离的 COM 对象”错误
【发布时间】:2013-05-18 11:50:21
【问题描述】:

我正在尝试在 .NET 4.0 之上编写一个 Windows 窗体程序并访问 Microsoft Access 数据库。我可以毫无问题地读写,但有时会出现此错误:

无法使用已与其底层 RCW 分离的 COM 对象。

我尝试使用不同的输入调用此方法 (GetIDBasedonTeamName) 两次(在同一个线程上)。第二次运行时,我得到了那个错误。

    OleDbConnection conn = new OleDbConnection();
    OleDbConnection mDB = new OleDbConnection();
    OleDbCommand comm = new OleDbCommand();
    OleDbCommand cmd;
    OleDbDataReader dr;

    public void OpenConnection(string name) // always call this method first in other methods to initialise connection
    {
        conn.ConnectionString = "Provider = Microsoft.Jet.OLEDB.4.0;Data source="
            + Application.StartupPath + "\\AppData\\" + name + ".mdb;";
        conn.Open();
        comm.Connection = conn;
        comm.Parameters.Clear();
    }

public string GetIDBasedonTeamName(string teamName)
    {
        string toReturn = "";

        try
        {
            OpenConnection("form");
            comm.CommandText = "Select ID from TeamDetails WHERE TeamName=@teamName";
            comm.Parameters.AddWithValue("TeamName", teamName);

            dr = comm.ExecuteReader();

            while (dr.Read())
            {
                toReturn = dr[0].ToString();
            }
        }
        catch (OleDbException e)
        {
            string err = e.Message.ToString();
            return null;
        }
        finally
        {
        }
        conn.Close();
        dr.Close();
        return toReturn;
    }

dr = comm.ExecuteReader(); 发生异常。

调用这个方法的方法里面有两行:

InfoConfig.team1id = Convert.ToInt32(dbm.GetIDBasedonTeamName(cbxTeam1.Text));
InfoConfig.team2id = Convert.ToInt32(dbm.GetIDBasedonTeamName(cbxTeam2.Text));

可能是什么原因?我读了一圈,他们提到不要使用不同的线程,但这里是同一个线程。

谢谢, 郭宏

【问题讨论】:

    标签: winforms ms-access


    【解决方案1】:

    基于 Martin Liversage 的回答:

    public string GetIDBasedonTeamName(string teamName) {
        var connString = "Provider = Microsoft.Jet.OLEDB.4.0;Data source="
            + Application.StartupPath + "\\AppData\\" + name + ".mdb;";
        using (var conn = new OleDbConnection(connString)) {
            conn.Open();
            using (var cmd = conn.CreateCommand()) {
                cmd.CommandText="Select ID from TeamDetails WHERE TeamName = @teamName";
                cmd.Parameters.AddWithValue("TeamName", teamName);
                using (var rdr = cmd.ExecuteReader()) {
                    if (rdr.Read()) {
                        return (string)rdr["TeamName"];
                    }
                    //if no valid results will return null
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      您应该在方法中创建、使用和关闭对象,而不是只创建一次对象并将它们存储在类的字段中。它可能是您最后调用的Close 释放底层 COM 对象的方法,在第二次调用时给您异常。

      【讨论】:

      • 所以你说我应该做“OleDbConnection conn = new OleDbConnection(); OleDbConnection mDB = new OleDbConnection(); OleDbCommand comm = new OleDbCommand(); OleDbCommand cmd; OleDbDataReader dr;”并在每种方法中打开连接?
      • @GuoHongLim:是的,浏览OleDbConnection 文档表明使用了连接池。然后,正确的模式是在 using 语句中临时创建必要的对象,就像在 the example 中所做的那样。
      猜你喜欢
      • 2021-09-23
      • 2011-03-11
      • 2011-04-26
      • 2012-04-23
      • 2011-11-21
      • 2012-04-27
      • 2011-07-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多