SqlConnection.Open() returns StackOverflow 异常

SqlConnection.Open() returns a StackOverflow Exception

我试图为此找到解决方案,但没有成功。问题来了:

我正在加载一组用户的数据并为每个用户创建一个对象。每个用户对象都有许多对象属性。结构如下:

public class User {
   public int ID { get; set; }
   public string Name { get; set; }
   public City City { get; set; }
   public Office Office { get; set; }
}

城市class:

public class City {
    public int ID { get; set; }
    public string Name { get; set; }
    public string Keyword { get; set; }
}

办公室class:

public class Office {
    public int ID { get; set; }
    public string Address { get; set; }
    public int CityID { get; set; }
}

用户对象还有许多其他类似的属性,例如 City 和 Office,它们基本上都是 class 个对象。

现在是主要问题。每当我尝试将所有用户加载到字典集合中时,Whosebug 异常发生在 SqlCon.Open() 处(请参阅我在下面编写的 "Fetch" 函数)。以下是我加载所有内容的方式:

//Code to load users
Dictionary<int, User> Users = new Dictionary<int, Users>();
DataTable usersData = new DataTable();

//The Fetch function has two version. The first one; which is mentioned in this post, returns the result as Dictionary<string, object>(). 
//The second version of the function returns the result in the form of the a DataTable and is only used when multiple rows are required from the database. The following returns a set of rows in a DataTable.

Globals.MainDatabase.Fetch("SELECT * FROM users", out usersData);

foreach (DataRow row in usersData.Rows) {
    User user = new User();
    user.ID = Convert.ToInt32(row["id"]);
    user.Name = row["name"].ToString();
    user.City = Cities.Get(Convert.ToInt32(row["city_id"]));
    user.Office = Offices.Get(Convert.ToInt32(row["office_id"]));
    Users.Add(user.ID, user);
}

"Cities.Get(Int32 id)" 和 "Offices.Get(Int32 id)" 方法使用以下函数从数据库中获取数据。

public void Fetch(string query, out Dictionary<string, object> results) {
        var dict = new Dictionary<string, object>();
        try {
            using (SqlConnection SqlCon = new SqlConnection(ConnectionString)) {
                using (SqlCmd = new SqlCommand()) {
                    SqlCmd.Connection = SqlCon;
                    SqlCmd.CommandType = CommandType.Text;
                    SqlCmd.CommandText = query;

                    SqlCon.Open();

                    DataTable temp = new DataTable();
                    using (SqlDataAdapter SqlAdp = new SqlDataAdapter(SqlCmd)) {
                        SqlAdp.SelectCommand = SqlCmd;
                        SqlAdp.Fill(temp);
                    }

                    DataRow row = temp.Rows[0];
                    temp = null;
                    dict = row.Table.Columns
                           .Cast<DataColumn>()
                           .ToDictionary(col => col.ColumnName, col => row.Field<object>(col.ColumnName));
                }
            }
        }
        catch (Exception ex) {
            HandleException(ex, "An error occurred when tried to fetch data.", query);
        }

        results = dict;
        dict = null;
    }

我意识到这个 "Fetch" 函数在创建用户对象时被多次调用。 "Whosebug" 异常恰好发生在这一行:

SqlCon.Open();

如何解决这个错误?或者我应该使用更好的方法来做到这一点?

评论有点长

  • 您真的需要从数据库加载 ALL 数据吗?最好只抓取你需要的列和行。
  • 为什么要将 DataTables 复制到 Dictionaries?只使用 DataTable 有什么问题?
  • 99.9% 的时间您将在数据库中执行 JOIN 秒时获得更好的性能。
  • 不要尝试自己动手 'ORM'。如果您不想要 EF 或 NHibernate 的膨胀,请使用 Dapper 之类的东西。或者,坚持使用 ADO(DataTableDataAdapter 等)
using (SqlConnection SqlCon = new SqlConnection(ConnectionString)) {

您的连接字符串变量真的名为 ConnectionString 吗?您是否有可能与类型发生名称冲突?由于它没有在显示的代码中声明,我假设它是一个 class 变量,所以你应该遵守传统的命名约定,即 _connectionString。您的连接字符串是什么样的?

好的伙计们,我明白了。这都是因为整个演示应用程序的错误架构。某些对象具有一个或多个其他对象作为属性,并且由于体系结构中的一些愚蠢错误;作为从数据库中获取数据的基础的 "fetch" 操作被递归调用,导致 Whosebug 异常,这实际上是大量数据库连接被初始化,最终将堆大小增加到导致异常的程度。

我试图总结上面段落中的所有内容,因为考虑到大量代码,post获取完整的源代码是无用的。

感谢所有提供帮助的人,尤其是@Guffa 对主要 post 的评论,这迫使我从头开始调查整个问题,而不是坚持使用异常堆栈。