I tried to find a solution for this but couldn't. Here's the problem:
I'm loading data of a bunch of users and creating an object for each user. Each user object has many object properties. Here's the structure:
public class User {
public int ID { get; set; }
public string Name { get; set; }
public City City { get; set; }
public Office Office { get; set; }
}
The City class:
public class City {
public int ID { get; set; }
public string Name { get; set; }
public string Keyword { get; set; }
}
The Office class:
public class Office {
public int ID { get; set; }
public string Address { get; set; }
public int CityID { get; set; }
}
The user object has many other similar properties like City & Office which are basically class objects.
Now here's the main issue. Whenever I try to load all the users into a collection of dictionary, StackOverflow exception occurs at SqlCon.Open() (See the "Fetch" function I've written below). Here's how I'm loading everything:
//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);
}
The methods "Cities.Get(Int32 id)" and "Offices.Get(Int32 id)" uses the following function to fetch data from the database.
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;
}
I realize that this "Fetch" function is being called multiple times when creating the user object. The "StackOverflow" exception occurs exactly at this line:
SqlCon.Open();
How can I solve this error? or probably I should use a better approach to do this?
Alright folks, I figured it out. It was all because of faulty architecture of the whole demo application. Some objects have one or more other objects as properties and due to some silly faults in the architecture; the "fetch" operation which serves as the base of fetching data from the database, was recursively called resulting into StackOverflow exception which was actually a large number of database connections being initialized ultimately growing the heap size to an extent which causes the exception.
I tried to summarize everything in the paragraph written above because posting the complete source code is useless considering the large amount of code.
Thank you everyone who helped, especially @Guffa's comment on the main post which forced me to investigate the whole issue from scratch rather than sticking to the exception stack.