I want to assign a List to a member variable (the variable is a List), but I always get error message: System.StackOverflowException was unhandled, I don't know why, please see my code below:
public class Employee
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
public int DeptID { get; set; }
}
public class Department
{
public int DeptID { get; set; }
public string DeptName { get; set; }
public List<Employee> Employees
{
set { Employees = value; }
//get { return EmployeeDataAccessLayer.getEmployeesByDeptID(DeptID); }
get { return Employees; }
}
}
public class EmployeeDataAccessLayer
{
public static List<Employee> getEmployeesByDeptID(int deptID)
{
string conStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sqlStr = "select * from tblemployee where deptid = :deptid order by employeeid asc";
List<Employee> employees = new List<Employee>();
using (OracleConnection ocon = new OracleConnection(conStr))
{
OracleCommand ocmd = new OracleCommand(sqlStr, ocon);
ocmd.Parameters.Add(":deptid", deptID);
ocmd.Connection.Open();
OracleDataReader rdr = ocmd.ExecuteReader();
while (rdr.Read())
{
Employee employee = new Employee();
employee.EmployeeID = Convert.ToInt32(rdr["EMPLOYEEID"]);
employee.EmployeeName = rdr["NAME"].ToString();
employee.DeptID = Convert.ToInt32(rdr["DEPTID"]);
employees.Add(employee);
}
}
return employees;
}
}
public class DepartmentDataAccessLayer
{
public static List<Department> getAllDepartments()
{
string conStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sqlStr = "select * from tbldepartment order by departmentid asc";
List<Department> depts = new List<Department>();
using (OracleConnection ocon = new OracleConnection(conStr))
{
OracleCommand ocmd = new OracleCommand(sqlStr, ocon);
ocmd.Connection.Open();
OracleDataReader rdr = ocmd.ExecuteReader();
while (rdr.Read())
{
Department dept = new Department();
dept.DeptID = Convert.ToInt32(rdr["DEPARTMENTID"]);
dept.DeptName = rdr["NAME"].ToString();
dept.Employees = EmployeeDataAccessLayer.getEmployeesByDeptID(dept.DeptID);
depts.Add(dept);
}
}
return depts;
}
}
so, I debug it and found the exception occured at:
set { Employees = value;}
see below screenshot:
I really don't know why, can you tell me the reason or give me some suggestions?
In your case, when you assign something to the Employees it's setter will trigger it again assigns to the same variable so the same process will continues and it's leads to a infinity assignments, that's why you are getting that Exception. to overcome this Change the property definition like this:
private List<Employee> _Employees
public List<Employee> Employees
{
set { _Employees = value; }
get { return _Employees; }
}
or like this:
public List<Employee> Employees { get; set; }
Because you're setting Employees to value which is setting Employees to value which is setting Employees to value which is setting.......etc etc until the stack overflows.
Because you're not using a private variable to hold employees, you can just use an auto-getter and -setter to set the value to itself, like your other properties:
public List<Employee> Employees { get; set; }
Otherwise, setup a private variable to hold the list of employees. This can be use
private List<Employee> _employees;
public List<Employee> Employees
{
set { _employees = value; }
get { return _employees; }
}
If you're setting a value in C# with get and set, all you'll need to do is
public List<Employee> Employees{get; set;}
With an empty get and set block, the value will be assigned automatically. In your code, you're essentially calling the set function for your variable over and over again until a StackOverflow exception occurs
More information on properties here
Related
I'm kind a new on c#. I have a problem with to store the className to list since i need to display all the class that teacher taught. On result, it turns out just the last class teacher taught. I did use join table between teacher and classes.
Model
public class Teacher
{
public int teacherId { get; set; }
public string teacherfName { get; set; }
public string teacherlName { get; set; }
public string className { get; set; }
public int classId { get; set; }
}
Controller
public Teacher FindTeacher(int id)
{
Teacher newTeacher = new Teacher();
MySqlConnection Conn = school.AccessDatabase();
Conn.Open();
MySqlCommand cmd = Conn.CreateCommand();
//SQL QUERY
cmd.CommandText = "Select * from teachers left join classes on teachers.teacherid=classes.teacherid where teachers.teacherid = " + id;
//Gather Result Set of Query into a variable
MySqlDataReader ResultSet = cmd.ExecuteReader();
while (ResultSet.Read())
{
int teacherId = (int)ResultSet["teacherId"];
string teacherfName=ResultSet["teacherfname"].ToString();
string teacherlName=ResultSet["teacherlname"].ToString();
newTeacher.teacherId = teacherId;
newTeacher.teacherFName = teacherFName;
newTeacher.teacherLName = teacherLName;
newTeacher.className = className;
newTeacher.classId = (int)ResultSet["classid"];
}
return newTeacher;
}
Your only returning one teacher if you want all the teachers your code should be:
public IEnumerable<Teacher> FindTeacher(int id)
{
//Lise here
List<Teacher> teachers = new List<Teacher>();
//note the using
using MySqlConnection Conn = school.AccessDatabase();
Conn.Open();
//note the using
using MySqlCommand cmd = Conn.CreateCommand();
//SQL QUERY
cmd.CommandText = "Select * from teachers left join classes on teachers.teacherid=classes.teacherid where teachers.teacherid = " + id;
//Gather Result Set of Query into a variable
MySqlDataReader ResultSet = cmd.ExecuteReader();
while (ResultSet.Read())
{
//new teacher in the loop
Teacher newTeacher = new Teacher();
int teacherId = (int)ResultSet["teacherId"];
string teacherfName=ResultSet["teacherfname"].ToString();
string teacherlName=ResultSet["teacherlname"].ToString();
newTeacher.teacherId = teacherId;
newTeacher.teacherFName = teacherFName;
newTeacher.teacherLName = teacherLName;
newTeacher.className = className;
newTeacher.classId = (int)ResultSet["classid"];
//add to the collection
teachers.Add(newTeacher);
}
//return the collection
return teachers;
}
If also added using statements. These are important to prevent memory leaks
Modify Teacher Class to be able to carry List of TeacherClass that correspond to one teacher:
Define New Class TeacherClass to Carry a TeacherClass Data
public class TeacherClass
{
public string Name { get; set; }
public int Id { get; set; }
}
Modify Teacher Class To have a List Of TeacherClass
public class Teacher
{
public int teacherId { get; set; }
public string teacherfName { get; set; }
public string teacherlName { get; set; }
public List<TeacherClass> classes { get; set; } = new List<TeacherClass>();
}
Then get your function to set this TeacherClass List in a loop:
public Teacher FindTeacher(int id)
{
Teacher newTeacher = new Teacher();
//note the using
using MySqlConnection Conn = school.AccessDatabase();
Conn.Open();
//note the using
using MySqlCommand cmd = Conn.CreateCommand();
//SQL QUERY
cmd.CommandText = "Select * from teachers left join classes on teachers.teacherid=classes.teacherid where teachers.teacherid = " + id;
//Gather Result Set of Query into a variable
MySqlDataReader ResultSet = cmd.ExecuteReader();
// Check if any rows retrieved
if (reader.HasRows)
{
// Iterate Over Rows
while (ResultSet.Read())
{
// Set Teacher Data Just Once
if(newTeacher.teacherId == 0){
newTeacher.teacherId = (int)ResultSet["teacherId"];;
newTeacher.teacherFName = ResultSet["teacherfname"].ToString();
newTeacher.teacherLName = ResultSet["teacherlname"].ToString();
}
// Add new TeacherClass data for this teacher
newTeacher.classes.Add(
new TeacherClass(){
Name = className, // className Check this variable as it is not declared
Id = (int)ResultSet["classid"]
});
}
}
return newTeacher;
}
I am consuming Wcf Service in Windows Form Application . I am trying to create user login system based on user emu type from sql database .When I enter the value 1 into textbox it should return full time employee method else value 2 into textbox it should return part time employee method but Its is not working according expectation ..
Here is Employee class code ....
[KnownType(typeof(FullTimeEmployee))]
[KnownType(typeof(PartTimeEmployee))]
[DataContract(Namespace = "http://pragimtech.com/Employee")]
public class Employee
{
private int _id;
private string _name;
private string _gender;
private DateTime _dateOfBirth;
[DataMember(Order = 1)]
public int Id
{
get { return _id; }
set { _id = value; }
}
[DataMember(Order = 2)]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember(Order = 3)]
public string Gender
{
get { return _gender; }
set { _gender = value; }
}
[DataMember(Order = 4)]
public DateTime DateOfBirth
{
get { return _dateOfBirth; }
set { _dateOfBirth = value; }
}
[DataMember(Order = 5)]
public EmployeeType Type { get; set; }
}
[DataContract(Name = "EmployeeType")]
public enum EmployeeType
{
[EnumMember]
FullTimeEmployee = 1,
[EnumMember]
PartTimeEmployee = 2
}
}
Here is my Full time and part time employee class inherit from Employee class...
public class FullTimeEmployee : Employee
{
public int AnnualSalary { get; set; }
}
public class PartTimeEmployee : Employee
{
public int HourlyPay { get; set; }
public int HoursWorked { get; set; }
}
Here is Method to Get Employee method to access employee based on employee type...
public Employee GetEmployee(int Id)
{
Employee employee = null;
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("spGetEmployee1", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter parameterId = new SqlParameter();
parameterId.ParameterName = "#EmployeeType";
parameterId.Value = Id;
cmd.Parameters.Add(parameterId);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
if ((EmployeeType)reader["EmployeeType"] == EmployeeType.FullTimeEmployee)
{
return employee;
} }
else if ((EmployeeType)reader["EmployeeType"] == EmployeeType.PartTimeEmployee)
{
return employee;
}
}
}
return employee;
}
Here is my Windows Form Application ......
private void button1_Click(object sender, EventArgs e)
{
MyService.HalifaxServiceClient myservice = new MyService.HalifaxServiceClient("NetTcpBinding_IHalifaxService");
MyService.Employee employee = myservice.GetEmployee(Convert.ToInt32(txt1.Text));
MyService.FullTimeEmployee ft = new MyService.FullTimeEmployee();
if (employee == myservice.GetEmployee(Convert.ToInt32(txt1.Text).CompareTo(employee.Type)))
{
FulltimeEmployeeLinkActivites();
}
else if (employee == myservice.GetEmployee(Convert.ToInt32(txt1.Text).CompareTo(employee.Type)))
{
PartTimeEmployeeActivities();
}
else
{
label4.Text = "No infomation found";
}
}
Here is screen shot when I run the application ...
The problem I see with your if / else is that the conditional statements are exactly the same. One way that you can branch based on the type of an object is with the is keyword.
if (employee is FullTimeEmployee)
{
FulltimeEmployeeLinkActivites();
}
else if (employee is PartTimeEmployee)
{
PartTimeEmployeeActivities();
}
else
{
label4.Text = "No information found";
}
I would also add that this is not necessarily best practice, however it should get you what you are asking for.
In addition to that, your method that returns the employee instance never returns an employee of a valid type. It doesn't appear that the GetEmployee method ever instantiates an employee instance. It looks like it is always returning null. Try returning instances of the proper type. You will also need to populate the instances with the data you need.
if ((EmployeeType)reader["EmployeeType"] == EmployeeType.FullTimeEmployee)
{
return new FullTimeEmployee();
}
else if ((EmployeeType)reader["EmployeeType"] == EmployeeType.PartTimeEmployee)
{
return new PartTimeEmployee();
}
You have a confusing naming in your elements and "employee" class does not seems to be populated in your data reader.
"FullTimeEmployee" is the name one of your classes and also the name of one of your enums. So is not safe to set your condition
(EmployeeType)reader["EmployeeType"] == EmployeeType.FullTimeEmployee
I can not be sure without the code of your spGetEmployee, but if it returns values from your table with those same names it could be safer to declare
while(reader.Read())
{
employee= new employee();
employee.Id= reader.GetInt32(0);
employee.Name= reader.GetString(1);
...
employee.EmployeeType=(EmployeeType)reader.GetInt32(4);
if(employee.EmployeeType== EmployeeType.FullTimeEmployee)
{
//Do extra work for this type of employee
...
return employee;
}
}
I have the following method in DAL which accepts the model OrderList and returns a List<OrderList>
public List<OrderList> GetOrderList(OrderList orderList)
{
...
return new List<OrderList>();
}
When I analyze using FXCop, it's saying DoNotExposeGenericLists Error
FXCop is saying this as resolution
"Change 'List<OrderList>' in 'OrderRelatedDataAccess.GetOrderList(OrderList)' to use
Collection<T>, ReadOnlyCollection<T> or KeyedCollection<K,V>"
How can I correct this?
My OrderList model is shown below
public int serialNumber { get; set; }
public int orderID { get; set; }
public int orderListID { get; set; }
public int productID { get; set; }
public int quantity { get; set; }
public long price { get; set; }
public string productName { get; set; }
Thanks.
Edit:
Code inside the method
List<OrderList> listOfOrderList = new List<OrderList>();
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand("sGetOrderListByOrderID", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#orderID", orderList.orderID);
connection.Open();
reader = command.ExecuteReader();
int sno = 0;
while (reader.Read())
{
long price = long.Parse(reader[4].ToString());
listOfOrderList.Add(new OrderList()
{
serialNumber = ++sno,
orderID = (int)reader[0],
productID = (int)reader[2],
quantity = (int)reader[3],
price = price,
productName = reader[5].ToString(),
});
}
connection.Close();
}
return listOfOrderList;
In your case its best to change the method signature to use an IList instead of List
public IList<OrderList> GetOrderList(OrderList orderList)
{
//get your data and build your list here
return new List<OrderList>();
}
See the differences between ICollection and IList in this answer
The answer is right there in the FxCop message. Just change the return type to be ICollection<OrderList>, like so:
public ICollection<OrderList> GetOrderList(OrderList orderList)
{
...
return new List<OrderList>();
}
While doing JSON example, I have reached a point where i have a gridview and it should be bind to datasource. The datasource is in Json object
The code
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Employee employee = new Employee();
var list = employee.CreateEmployees();
var query = from emp in list.AsEnumerable()
select new
{
id = (int)emp.EmployeeId,
name = (string)emp.Name,
nic = (string)emp.Nic,
salary = (int)emp.Salary
};
JObject o = JObject.FromObject(new
{
Employees = query
});
Response.Write(o);
Session["JsonEmployee"] = o;
}
LoadGrid();
}
For loading Grid:
void LoadGrid() {
List<Employee> lst = new List<Employee>();
var objects = (JObject)Session["JsonEmployee"];
foreach (var v in objects)
{
lst = JsonConvert.DeserializeObject<List<Employee>>(v.Value.ToString());
}
GridView1.DataSource = lst;
GridView1.DataBind();
}
All works fine but the only problem is that the EmployeeId is 0 for every employee.
Employee class is as:
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Nic { get; set; }
public int Salary { get; set; }
.....
}
Note in the json object every employee has correct id but when it convert it to list getting employeeid 0 for every employee.
In the one object it's called id and in the other EmployeeId. Name them the same, it should solve the issue
Consider a Winforms app connecting to a SQL Server 2008 database and running a SQL SELECT statement:
string myConnectionString = "Provider=SQLOLEDB;Data Source=hermes;Initial Catalog=qcvaluestest;Integrated Security=SSPI;";
string mySelectQuery = "SELECT top 500 name, finalconc from qvalues where rowid between 0 and 25000;";
OleDbConnection myConnection = new OleDbConnection(myConnectionString);
OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection);
myCommand.Connection.Open();
OleDbDataReader myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
How can you read the results of the query into a list?
Assume you have defined a class that is something like
class MyData
{
public string Name {get; set;}
public int FinalConc {get; set;} // or whatever the type should be
}
You would iterate through the results of your query to load a list.
List<MyData> list = new List<MyData>();
while (myReader.Read())
{
MyData data = new MyData();
data.Name = (string)myReader["name"];
data.FinalConc = (int)myReader["finalconc"]; // or whatever the type should be
list.Add(data);
}
// work with the list
If you just need one of the given fields, you can forego the class definition and simply have a List<T>, where T is the type of whatever field you want to hold.
You can try something as (adapt it for your convenience):
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
List<Person> dbItems = new List<Person>();
while(myReader.Read())
{
Person objPerson = new Person();
objPerson.Name = Convert.ToString(myReader["Name"]);
objPerson.Age = Convert.ToInt32(myReader["Age"]);
dbItems.Add(objPerson);
}
List of what? Do you have a class setup that has properties for name and finalconc? Saying you do, and it looks like this:
public class QueryResult
{
public string Name { get; set; }
//not sure what finalconc type would be, so here just using string
public string FinalConc { get; set; }
}
Then you would do something like this:
var queryResults = new List<QueryResult>();
using(var myReader = myCommand.ExecuteReader())
{
while(myReader.Read())
{
queryResults.Add(new QueryResult
{
Name = myReader.GetString(myReader.GetOrdinal("name")),
FinalConc = myReader.GetString(myReader.GetOrdinal("finalconc"))
});
}
}