Create a new object each loop - c#

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);

Related

How do I read SQL row values of a column into an array?

I have created a method that will get data from a SQL table and store the columns of data each in their own array. Right now, when working through the debugger, what I notice is that when I am assigning values to these arrays, they are null values.
I did check to see if my query returns values in SSMS and it indeed does. So null values should not be expected.
Here is the code to the method:
public static CommentsPageData getComments(string wcNum)
{
string[] prodTimeArray = new string[24];
string[] crewsArray = new string[24];
string[] commentsArray = new string[24];
string[] redTimeArray = new string[24];
string[] greenTimeArray = new string[24];
string commandSql = "SELECT TOP 24 Production_Time, Crew, Red_Time, Green_Time, Comment FROM ************ WHERE Work_Center = #wc ORDER BY Production_Time DESC";
SqlConnection con = new SqlConnection("Data Source=*******;Initial Catalog=********;Integrated Security=True");
con.Open();
SqlCommand cmd = new SqlCommand(commandSql, con);
cmd.Parameters.AddWithValue("wc", wcNum);
CommentsPageData commPageData = new CommentsPageData();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
prodTimeArray.Append(reader["Production_Time"].ToString());
crewsArray.Append(reader["Crew"].ToString());
redTimeArray.Append(reader["Red_Time"].ToString());
greenTimeArray.Append(reader["Green_Time"].ToString());
commentsArray.Append(reader["Comment"].ToString());
}
}
else
{
Console.WriteLine("No rows found");
}
reader.Close();
}
commPageData.ProdTimes = prodTimeArray;
commPageData.Crews = crewsArray;
commPageData.GreenTime = greenTimeArray;
commPageData.RedTime = redTimeArray;
commPageData.Comments = commentsArray;
con.Close();
return commPageData;
}
Long story short, I have created a Class (CommentsPageData) which has an array for each column I'm returning 24 values from. However... The problem is in the while(reader.Read()){} section of the method. I can see it assigning values, but it is just assigning null values.
How can I actually get the values and assign them to my array correctly?
Its just like Jeroen Mostert said, Arrays in C# do not change in size after they are declared. You have declared your arrays inside the class which means the size you have initialized your arrays with is 0 which means no matter how many times you try to append elements to them, the arrays will be null. Use System.Collections.Generic List<Type> to hold your data as it can be updated to hold more elements.
public static CommentsPageData getComments(string wcNum)
{
List<string> prodTimeArray = new List<string>();
List<string> crewsArray = new List<string>();
List<string> commentsArray = new List<string>();
List<string> redTimeArray = new List<string>();
List<string> greenTimeArray = new List<string>();
string commandSql = "SELECT TOP 24 Production_Time, Crew, Red_Time, Green_Time, Comment FROM ************ WHERE Work_Center = #wc ORDER BY Production_Time DESC";
SqlConnection con = new SqlConnection("Data Source=*******;Initial Catalog=********;Integrated Security=True");
con.Open();
SqlCommand cmd = new SqlCommand(commandSql, con);
cmd.Parameters.AddWithValue("wc", wcNum);
CommentsPageData commPageData = new CommentsPageData();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
prodTimeArray.Add(reader["Production_Time"].ToString());
crewsArray.Add(reader["Crew"].ToString());
redTimeArray.Add(reader["Red_Time"].ToString());
greenTimeArray.Add(reader["Green_Time"].ToString());
commentsArray.Add(reader["Comment"].ToString());
}
}
else
{
Console.WriteLine("No rows found");
}
reader.Close();
}
commPageData.ProdTimes = prodTimeArray.ToArray();
commPageData.Crews = crewsArray.ToArray();
commPageData.GreenTime = greenTimeArray.ToArray();
commPageData.RedTime = redTimeArray.ToArray();
commPageData.Comments = commentsArray.ToArray();
con.Close();
return commPageData;
}
I would use this code
reader = cmd.ExecuteReader()
var dt=new DataTable;
dt.Load(reader);
Dictionary<string, string[]> dict = new();
for (var i = 0; i < dt.Rows.Count; i++)
{
for (var j = 0; j < dt.Rows[i].ItemArray.Length; j++)
{
if (!dict.ContainsKey(dt.Columns[j].ColumnName))
dict.Add(dt.Columns[j].ColumnName, new string[dt.Rows.Count]);
dict[dt.Columns[j].ColumnName][i] = dt.Rows[i].ItemArray[j].ToString();
}
}
and just use the dictionary
but if you want a name for each array
string[] prodTimeArray;
string[] crewsArray;
string[] commentsArray;
....
prodTimeArray = dict["Production_Time"];
crewsArray = dict["Crew"];
commentsArray = dict["Comment"];
....
If you really need to have this end result, I'd recommend just making an object representing a row in the table, use Dapper to return the rows into an IEnumerable of the objects, then to a LINQ select for each column into an array
For Example:
var results = await con.QueryAsync<MyRowObject>(commandSql, new {"wc"}, commandType: Text);
var productionTimeArray = results.Select(x => x.ProductionTime).ToArray();

Return an Empty list rather than throwing null exception in c#

I am writing a sql service to Get the list of items for a service.
The method looks like this,
public List<Items> GetList(string username)
{
string sql = "Select * From Items Where username = '{0}'";
sql = string.Format(sql, Username);
return base.Get(sql);
}
Get method does all the code to get the data from the database and return to the list.
My question is when the username doesn't exist in the database it is throwing exception 'object reference not set to instance of an object'. Instead of throwing exception i want to return an empty List of items. The Item object consists of properties(ItemID, ItemName, ItemPlace)
or Give me any suggestions to implement it in a different way.
ItemID = null,
ItemName = null,
ItemPlace = null
take a look on the code, you have to modify your code accordingly.
Public List<Items> Get(string sql)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
var ItemsList = new List<Items>();
var Items = new Items()
SqlCommand command = new SqlCommand(sql, connection);
SqlDataReader dr = command.ExecuteReader();
dr = cmd.ExecuteReader();
while (dr.Read())
{
Items.ItemID = dr["ItemID"].ToString();
Items.ItemName = dr["ItemName"].ToString();
Items.ItemPlace = dr["ItemPlace"].ToString();
ItemsList.Add(Items);
}
if(ItemsList.Count == 0)
{
Items.ItemID = null;
Items.ItemName = null;
Items.ItemPlace = null;
ItemsList.Add(Items);
}
return ItemsList;
}
}

How to loop through list of complex type objects and pass to a method calling SQL Stored procedure

How to loop through a list of objects in order to pass said object to a method inserting rows in SQL db via stored procedure?
With help in this question I got to this point:
namespace NA.Controllers
{
public class NC : ApiController
{
[Route("AddNote")]
[HttpPost]
public HttpResponseMessage PostNote(List<Note> items)
{
//NoteJson deserializednote = JsonConvert.DeserializeObject<NoteJson>(item);
//Note notesdata = new Note(item);
NotesAccept.Models.INoteRepository Repository = new NotesAccept.Models.NoteDataRepository();
foreach (Note item in items)
{
item = Repository.Add(item);
}
var response = Request.CreateResponse<List<Note>>(HttpStatusCode.OK, items);
return response;
}
}
}
but now I'm stuck as item= is now an iteration variable, but I need to pass it to an method:
namespace NA.Models
{
class NoteDataRepository : INoteRepository
{
public void Add(Note item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
else
{
String strConnString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "BL_IntegrationInsertNote";
cmd.Parameters.Add("#Client", SqlDbType.VarChar).Value = item.Client.Trim();
cmd.Parameters.Add("#Case", SqlDbType.VarChar).Value = item.Case;
cmd.Parameters.Add("#Text", SqlDbType.VarChar).Value = item.Text.Trim();
cmd.Parameters.Add("#When", SqlDbType.DateTime).Value = item.Date;
cmd.Parameters.Add("#Ext", SqlDbType.Bit).Value = item.Type;
cmd.Parameters.Add("#return", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
string id = cmd.Parameters["#return"].Value.ToString();
string lblMessage = null;
lblMessage = "Record inserted successfully. ID = " + id;
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
}
//return item;
}
IEnumerable<Note> INoteRepository.GetAll()
{
throw new NotImplementedException("getitems");
}
}
}
I'm still green-as-a-grass-newbie to C# so I've no idea how to accomplish that, especially since whole solution is still "copy&Paste" from all over the web, and whole web curiously concentrates on looping through simple types. How to do that with complex type?
As noted in other question, this is a matter of professional life and death (I'm a db dev, not a VS guru, especially not after two days and two nights).
You are still forgetting to assign that ID from DB to the item.
You also still have
return item;
in a method that does not return anything (public void Add(Note item)).
So just delete that return line.
And replace
item = Repository.Add(item);
with just
Repository.Add(item);
You can pass it as xml and iterate in sql stored procedure and do bulk insert, or you can use table datatype if sql and .net version you are using supports it.
Try this in the foreach loop:
var tempItem = item;
tempItem = Repository.Add(tempItem);

How to create a Dynamic IEnumerable

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;
}

Return a List after reading from the Database

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;
}

Categories

Resources