I know this is a simple question for you. But I am a beginner in c#.
What I want to achieve is to create a method that will store any type of List of Objects from my Model. e.g List<Person>.
I have tried to make something like this..
public IEnumerable<T> GetObjects<T>()
{
Type type = typeof(T);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo item in properties)
{
// store properties
}
List<T> objects = new List<T>();
using (SqlConnection str = GetSqlConnection)
{
// retrieve data from db
//then store it to list of objects
}
return objects;
}
This will enable me to retrieve data using only this method.
EDIT:
I already manage to create this sample code to retrieve a specific table from a database.
public IEnumerable<ItemBrand> getAllBrand
{
get
{
List<ItemBrand> brands = new List<ItemBrand>();
using (MySqlConnection strConn = getMySqlConnection())
{
string query = "SELECT * FROM tblbrand";
MySqlCommand cmd = new MySqlCommand(query, strConn);
strConn.Open();
MySqlDataReader rd = cmd.ExecuteReader();
while (rd.Read())
{
ItemBrand brand = new ItemBrand();
brand.brandID = Convert.ToInt32(rd["brandID"]);
brand.Name = rd["brandName"].ToString();
brands.Add(brand);
}
return brands;
}
}
}
Currently I have multiple methods of this in my solution. I would love to remove those duplicate codes with your help.
<code>
// Create a new type of the entity I want
Type t = typeof(T);
T returnObject = new T();
for (int i = 0; i < dataReader.FieldCount; i++) {
string colName = string.Empty;
colName = dataReader.GetName(i);
// Look for the object's property with the columns name, ignore case
PropertyInfo pInfo = t.GetProperty(colName.ToLower(), BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
// did we find the property ?
if (pInfo != null) {
if (dataReader.Read()) {
object val = dataReader[colName];
// is this a Nullable<> type
bool IsNullable = (Nullable.GetUnderlyingType(pInfo.PropertyType) != null);
if (IsNullable) {
if (val is System.DBNull) {
val = null;
} else {
// Convert the db type into the T we have in our Nullable<T> type
val = Convert.ChangeType(val, Nullable.GetUnderlyingType(pInfo.PropertyType));
}
} else {
// Convert the db type into the type of the property in our entity
val = Convert.ChangeType(val, pInfo.PropertyType);
}
// Set the value of the property with the value from the db
pInfo.SetValue(returnObject, val, null);
}
}
}
</code>
Have a generic method like:
public IEnumerable<T> CreateListOfItems(string tableName,
Func<MySqlDataReader, T> itemCreator)
{
var items = new List<T>();
using (var strConn = getMySqlConnection())
{
string query = "SELECT * FROM " + tableName;
var cmd = new MySqlCommand(query, strConn);
strConn.Open();
var rd = cmd.ExecuteReader();
while (rd.Read())
{
items.Add(itemCreator(rd));
}
}
return items;
}
Then use like this:
private ItemBrand CreateItemBrandFromDBData(MySqlDataReader rd)
{
return new ItemBrand
{
BrandID = Convert.ToInt32(rd["brandID"]),
Name = rd["brandName"].ToString()
};
}
...
var brands = CreateListOfItems<ItemBrand>(tblbrand, CreateItemBrandFromDBData);
I have written a method that gets the result retrieved from a stored proc and transformes it into a list of objects.
The only thing you need to pay attention to is:
The class you are mapping to must have the same column names as the ones that are sent from the database.
public IEnumerable <T> ExecuteReaderToList<T>(string storedProcedure, IDictionary parameters = null,
string connectionString = null)
{
ICollection list = new List();
var properties = typeof(T).GetProperties();
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = storedProcedure;
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null)
{
foreach (KeyValuePair<string, object> parameter in parameters)
{
cmd.Parameters.AddWithValue(parameter.Key, parameter.Value);
}
}
cmd.Connection = conn;
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var element = Activator.CreateInstance<T>();
foreach (var f in properties)
{
var o = reader[f.Name];
if (o.GetType() != typeof(DBNull))
{
f.SetValue(element, o, null);
}
o = null;
}
list.Add(element);
}
}
conn.Close();
}
return list;
}
Related
I facing a strange problem, when I execute the code below for second time I got an exception
this method exists inside DB context (entity framework core)
Code:
public IEnumerable<T> ExecuteStoredProcedure<T>(string spname, params object[] ps)
{
string json = string.Empty;
using (var sqlConnection = (SqlConnection)this.Database.GetDbConnection())
{
var command = sqlConnection.CreateCommand();
command.CommandText = spname;
command.CommandType = System.Data.CommandType.StoredProcedure;
for (int i = 0; i < ps.Length; i++)
{
var obj = ps[i];
System.Reflection.PropertyInfo nameprop = obj.GetType().GetProperty("name");
string name = (string)(nameprop.GetValue(obj, null));
System.Reflection.PropertyInfo valprop = obj.GetType().GetProperty("value");
dynamic val = (dynamic)(valprop.GetValue(obj, null));
command.Parameters.Add(new SqlParameter(name, val));
}
this.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
var rawdata = Serialize(result);
json = JsonConvert.SerializeObject(rawdata, Formatting.Indented);
}
}
return JsonConvert.DeserializeObject<IEnumerable<T>>(json);
}
Exception
System.InvalidOperationException: 'The ConnectionString property has not been initialized.'
I have solved this issue by remove using
public IEnumerable<T> ExecuteStoredProcedure<T>(string spname, params object[] ps)
{
string json = string.Empty;
var sqlConnection = (SqlConnection)this.Database.GetDbConnection();
var command = sqlConnection.CreateCommand();
command.CommandText = spname;
command.CommandType = System.Data.CommandType.StoredProcedure;
for (int i = 0; i < ps.Length; i++)
{
var obj = ps[i];
System.Reflection.PropertyInfo nameprop = obj.GetType().GetProperty("name");
string name = (string)(nameprop.GetValue(obj, null));
System.Reflection.PropertyInfo valprop = obj.GetType().GetProperty("value");
dynamic val = (dynamic)(valprop.GetValue(obj, null));
command.Parameters.Add(new SqlParameter(name, val));
}
this.Database.OpenConnection();
var result = command.ExecuteReader();
var rawdata = Serialize(result);
json = JsonConvert.SerializeObject(rawdata, Formatting.Indented);
return JsonConvert.DeserializeObject<IEnumerable<T>>(json);
}
When you leave your "using" block, .NET runtime will call the Dispose() method of the variable for you. So by the second time the method is called, your static connection variable is no longer valid.
Try remove the using statement from your method and you'll be fine.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ae6780da-7ad6-4e90-977e-7b0a71345be8/the-connectionstring-property-has-not-been-initialized-random-error?forum=csharpgeneral
I have a while loop inside a database connection, where I want to create an object from the values retrieved from the database.
This is the code I used:
public void dbConnect()
{
using (SqlConnection myConnection = new SqlConnection("server=CHAYU\\SQLEXPRESS;" +
"Trusted_Connection=yes;" +
"database=restaurantApp; " +
"connection timeout=30"))
{
string oString = "Select * from Meal where availability=1";
SqlCommand oCmd = new SqlCommand(oString, myConnection);
myConnection.Open();
using (SqlDataReader oReader = oCmd.ExecuteReader())
{
while (oReader.Read())
{
Meal m = new Meal();
m.mealID = Convert.ToInt32(oReader["mealId"]);
m.mealName = oReader["mealName"].ToString();
m.quantity=Convert.ToInt32(oReader["quantity"]);
m.timeToProduce = Convert.ToInt32(oReader["timeToProduce"]);
m.availability = true;
}
myConnection.Close();
}
}
}
I want to call this code each time the form loads, so that the objects are created at the beginning, and they can later be manipulated. But, my problem is, how do I do so, by having a different reference variable to the object, inside the while loop?
Do you want to have each meal? Create a list and store your meal objects while iterating in it!
List<Meal> mList = new List<Meal>();
while (oReader.Read())
{
Meal m = new Meal();
m.mealID = Convert.ToInt32(oReader["mealId"]);
m.mealName = oReader["mealName"].ToString();
m.quantity = Convert.ToInt32(oReader["quantity"]);
m.timeToProduce = Convert.ToInt32(oReader["timeToProduce"]);
m.availability = true;
mList.Add(m);
}
Add each created object in the loop to a List. By default each Meal being created in your loop is a different reference, but you're not storing them anywhere to manipulate later.
Use this extension method Get list of object in your datareder class
public static List<T> DataReaderMapToList<T>(IDataReader dr)
{
List<T> list = new List<T>();
T obj = default(T);
while (dr.Read()) {
obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in obj.GetType().GetProperties()) {
if (!object.Equals(dr[prop.Name], DBNull.Value)) {
prop.SetValue(obj, dr[prop.Name], null);
}
}
list.Add(obj);
}
return list;
}
Then use it like this
List<Meal> MealList = new List<Meal>();
MealList = DataReaderMapToList<Meal>(reader);
In my data access layer I have a class called Execute. class Execute is used to make transactions with data base.
I have another class called Table1DataAceess to communicate with Execute class and BusinessLogicClass1 to communicate with Data Access Layer. Eg: Picture
I have only 4 method to do any transaction with the data base (Insert,Update,Delete,Retrieve).
In the Retrieving method, I wanna implement to get any return type without pre-defining the return type.
Eg: If I want to get a List of VehicleModel data , In my Table1DataAceess class, I just need to write
Execute DBExe = new Execute();
List<VehicleModel> vList = DBExe<List<VehicleModel>,VehicleModel>(spName,model);
//If I wanna take it into a DataTable
DataTable dt = DBExe<DataTable,VehicleModel>(spName,model);
There for I have develop following method,
public T SpExecutesNew<T,T1>(string cmdText, T1 item) where T : new()
{
DataSet ds = new DataSet();
SqlDataAdapter ad = new SqlDataAdapter();
SqlCmd = new SqlCommand();
SqlConnection conn = null;
try
{
conn = clsConnection.OpenConnectiion();
SqlCmd.Connection = conn;
SqlCmd.CommandText = cmdText;
SqlCmd.CommandType = CommandType.StoredProcedure;
SqlCmd.CommandTimeout = 100;
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
SqlCommandBuilder.DeriveParameters(SqlCmd);
foreach (SqlParameter prr in SqlCmd.Parameters)
{
bool found = false;
if (prr.ParameterName.ToUpper() == "#RETURN_VALUE")
continue;
for (int i = 0; i < Props.Length && !found; i++)
{
string prName = "#" + Props[i].Name;
if (prr.ParameterName == prName)
{
prr.Value = Props[i].GetValue(item, null);
found = true;
}
}
}
ad = new SqlDataAdapter(SqlCmd);
ad.Fill(ds);
//List<T> list = new List<T>();
///STIL IMPLIMENTING...
////return (T)Convert.ChangeType(ds.Tables[0], typeof(T));
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn != null && conn.State == ConnectionState.Open)
conn.Close();
if (conn != null)
conn.Dispose();
SqlCmd = null;
}
}
I have no idea about how to create this return type "T" with data. because if it is a list, then I have to fill the list and return as a list.
(method should return the T as a List) But how to create the list as T.
Please help..
Here is an example
This is method of DbAccess layer.This method will executereader you can even fill datatable and convert it to list.
public List<T> ReturnList<T>(CommandType commandType, string commandText, List<SqlParameter> parameters) where T : new()
{
SqlDataReader reader = null;
try
{
CreateConnection();
command = new SqlCommand();
BuildCommand(command, commandType, commandText, conn);
AddParametersToCommand(parameters, command);
reader = command.ExecuteReader();
List<T> list = CommonMethods.ToList<T>(reader);
reader.Close();
reader.Dispose();
CloseConnection();
return list;
}
catch (Exception ex)
{
reader.Close();
reader.Dispose();
conn.Close();
throw ex;
}
finally
{
}
}
This is the code which will convert the datatable or sqldatareader to any given class list
CommonMethods.Cs
public static class CommonMethods
{
public static List<T> ToList<T>(DataTable datatable) where T : new()
{
List<T> Temp = new List<T>();
try
{
List<string> columnsNames = new List<string>();
foreach (DataColumn DataColumn in datatable.Columns)
columnsNames.Add(DataColumn.ColumnName);
Temp = datatable.AsEnumerable().ToList().ConvertAll<T>(row => getObject<T>(row, columnsNames));
return Temp;
}
catch { return Temp; }
}
private static T getObject<T>(DataRow row, List<string> columnsName) where T : new()
{
T obj = new T();
try
{
string columnname = "";
string value = "";
PropertyInfo[] Properties; Properties = typeof(T).GetProperties();
foreach (PropertyInfo objProperty in Properties)
{
columnname = columnsName.Find(name => name.ToLower() == objProperty.Name.ToLower());
if (!string.IsNullOrEmpty(columnname))
{
value = row[columnname].ToString();
if (!string.IsNullOrEmpty(value))
{
if (Nullable.GetUnderlyingType(objProperty.PropertyType) != null)
{
value = row[columnname].ToString().Replace("$", "").Replace(",", "");
objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(Nullable.GetUnderlyingType(objProperty.PropertyType).ToString())), null);
}
else
{
value = row[columnname].ToString().Replace("%", "");
objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(objProperty.PropertyType.ToString())), null);
}
}
}
} return obj;
}
catch { return obj; }
}
public static List<T> ToList<T>(SqlDataReader dataReader) where T : new()
{
List<T> res = new List<T>();
while (dataReader.Read())
{
T t = new T();
for (int inc = 0; inc < dataReader.FieldCount; inc++)
{
Type type = t.GetType();
PropertyInfo prop = type.GetProperty(dataReader.GetName(inc));
prop.SetValue(t, dataReader.GetValue(inc), null);
}
res.Add(t);
}
return res;
}
}
And Here is how you will call it
List<YourClassName> list = DbAccess.ReturnList<YourClassName>(System.Data.CommandType.StoredProcedure, "searchappointments", listParams);
I've got a data access layer to which I am binding some controls. Currently I have something along the lines of
public List<Race> GetRaces()
{
List<Race> raceList = new List<Race>();
using (var con = new SqlConnection(this.ConnectionString))
{
using (var cmd = new SqlCommand("spGetRace",con))
{
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Race r = new Race();
r.RaceId = Convert.ToInt32(rdr["raceId"]);
r.RaceDescription = rdr["RaceDescription"].ToString();
raceList.Add(r);
}
}
return raceList;
}
}
public List<Ses> GetSes()
{
List<Ses> sesList = new List<Ses>();
using (var con = new SqlConnection(this.ConnectionString))
{
using (var cmd = new SqlCommand("spGetSes",con))
{
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Ses s = new Ses();
s.SesId = Convert.ToInt32(rdr["SesId"]);
s.SesDescription = rdr["SesDescription"].ToString();
sesList.Add(s);
}
}
return sesList;
}
}
which will be bound to drop down lists in my presentation layer. Instead of having to type the lion's share of this ADO.NET code over and over, what are some useful refactoring techniques for this basic type of data access? Can I do this by refactoring with a SqlConnection, SqlCommand, and one of my custom types Race/Ses as a parameter?
public enum SqlCommandNames
{
spGetRace,
spGetSes ,
spGetOthers
}
public class myobj{
public int id {get;set;}
public string description {get;set}
}
public List<myobj> GetObj(SqlCommandNames sqlcmd)
{
List<myobj> objList = new List<myobj>();
using (var con = new SqlConnection(this.ConnectionString))
{
using (var cmd = new SqlCommand(sqlcmd.ToString(),con))
{
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
myobj r = new myobj();
r.id = = reader.GetInt32(0);
r.description = reader.IsDBNull(1) ? "" : reader.GetString(1);
objList.Add(r);
}
}
return objList;
}
}
Additional advice will be to cache lists
List<myobj> objList = (List<myobj>)HttpContext.Current.Cache[sqlcmd.ToString()];
if (objList == null)
{
List<myobj> objList = new List<myobj>();
HttpContext.Current.Cache.Insert(sqlcmd.ToString(), objList);
....
....
}
//and caching all on start up
protected void Application_Start()
{
foreach (SqlCommandNames x in Enum.GetValues(typeof(SqlCommandNames)))
{
GetObj(x);
}
}
I am trying to retrieve all Names, from the Names tables in the database. I am unable to retrieve the data and return it as a lIst. how can i do it ?
public List<SelectListItem> getNames()
{
try
{
using (SqlCommand com = new SqlCommand("SELECT * FROM Names", con))
{
con();
SqlDataReader dr = com.ExecuteReader();
return ?? // How to return the items that was returned
}
}
.......
You can iterate over all rows returned as follows:
var items = new List<SelectListItem>();
while (dr.Read())
{
var valueInColumn1 = dr[1];
var valueInNamedColumn = dr["ColumnName"];
...
items.Add(new SelectListItem { Text = valueInColumn1.ToString(), Value = valueInNamedColumn.ToString());
}
return items;
First instantiate the list to hold your items (you could also leave it null but that depends on what your callers expect) and then iterate over the datareader by calling Read() until it returns false, which means no more records are available.
When the datareader has records you can fetch a column by calling one of the methods GetString, GetInt, GetLong etc supplying it the column you want to fetch as a parameter.
Construct the type you want to store in your list and add the retrieved values to its properties, add the new type to the List.
public List<SelectListItem> getNames()
{
var list = new List<SelectListItem>();
try
{
using (SqlCommand com = new SqlCommand("SELECT * FROM Names", con))
{
con();
SqlDataReader dr = com.ExecuteReader();
while (dr.Read())
{
list.Add(new SelectListItem {
Value = dr.GetString(0), // first column, depends on your table
Text = dr.GetString(1) // second column, depends on your table
});
}
catch(Exception e)
{
Trace.WriteLine(r.Message);
}
return list;
}
See my code example:
public static List<ActionItem> GetAllActions()
{
var actionItems = new List<ActionItem>();
SqlDataReader actionsReader = CatalogDB.GetAllActions();
try
{
while (actionsReader.Read())
{
actionItems.Add(new ActionItem
{
Id = (int)actionsReader["Id"],
Name = actionsReader["Name"] != DBNull.Value ? (string)actionsReader["Name"] : null,
Description = (string)actionsReader["Description"],
CreationDate = (DateTime)actionsReader["CreationDate"]
}
);
}
}
finally
{
actionsReader.Close();
}
return actionItems;
}
There are a couple of different ways, but this is probably the most straight forward.
public List<SelectListItem> getNames()
{
var list = new List<SelectedListItem>();
try
{
using (SqlCommand com = new SqlCommand("SELECT * FROM Names", con))
{
con();
SqlDataReader dr = com.ExecuteReader();
while (dr.Read())
{
var item = new SelectedListItem();
item.Value = dr[0];
list.Add(item);
}
}
}
catch(Exception ex)
{
// ...
}
return list;
}