.net How to add Add to nested list object - c#

I have the following class object
I fill a DataTable with data from my sp and the message from the DebtAllOut class
I roll through the DataTable and filling a list
public class DebtAllOut
{
public string message { get; set; }
public List<DebtAllDetail> debtalldetail { get; set; }
}
public class DebtAllDetail
{
public int debtid { get; set; }
public string name { get; set; }
}
var debtallout = new DebtAllOut();
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#ProfileID", profileid);
DataTable dt = new DataTable();
da.Fill(dt);
debtallout.message = "Providing general message";
List<DebtSingleOut> lstDebtSingleOut = new List<DebtSingleOut>();
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
DebtSingleOut debtsingleout = new DebtSingleOut();
if (dt.Rows[i]["RowID"] != DBNull.Value) {
debtsingleout.debtid = Convert.ToInt32(dt.Rows[i] ["RowID"]);
}
lstDebtSingleOut.Add(debtsingleout);
}
}
debtallout.debtalldetail.AddRange(lstDebtSingleOut);
The last line gives the the error. When I try to add the list to the debtalldetail nested class
debtallout.debtalldetail.AddRange(lstDebtSingleOut);
The error I receive is
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.List<mystuff.Models.DebtSingleOut>' to 'System.Collections.Generic.IEnumerable<mystuff.Models.DebtAllDetail>'

You're trying to add a list lstDebtSingleOut of type List<DebtSingleOut> to the debtalldetail property which is of type List<DebtAllDetail>. It's not easy to understand full logic but I think you mixed up classes DebtAllDetail and DebtSingleOut.
You need to create a new DebtAllDetail object for each row and add it to the debtalldetail list or you can fix the code change the type to the necessary.
var debtallout = new DebtAllOut();
debtallout.message = "Providing general message;"
// inirialize new instance of List<DebtAllDetail> to add elements
debtallout.debtalldetail = new List<DebtAllDetail>();
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#ProfileID", profileid);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
// create and initialize new DebtAllDetail object
DebtAllDetail debtAllDetail = new DebtAllDetail();
if (dt.Rows[i]["RowID"] != DBNull.Value)
debtAllDetail.debtid = Convert.ToInt32(dt.Rows[i]["RowID"]);
if (dt.Rows[i]["Name"] != DBNull.Value)
debtAllDetail.name = dt.Rows[i]["Name"].ToString(); // or another code to retrieve the name
// add initialized DebtAllDetail object to list
debtallout.debtalldetail.Add(debtAllDetail);
}
}

Given this class definition:
public class DebtAllOut
{
public string message { get; set; }
public List<DebtAllDetail> debtalldetail { get; set; }
}
It's important to understand the result of this line:
var debtallout = new DebtAllOut();
At this point, the value of debtallout.debtalldetail is still null!
This is because the class definition did not specify to actually create the list object. It only specified to create a variable that might (or might not) refer to some list variable. That is, you have a reference, but the reference doesn't refer to anything yet.
You can fix it in two ways. First, by changing the class definition:
public class DebtAllOut
{
public string message { get; set; }
public List<DebtAllDetail> debtalldetail { get; private set; } = new List<DebtAllDetail>();
}
(Notice the use of private. You will still be able to add or remove items from the list, because accessing members of the list, including methods like Add(), is still a get operation.)
The second fix is to manually create a new list instance:
var debtallout = new DebtAllOut();
debtallout.debtalldetail = new List<DebtAllDetail>();
But all that aside, we can significantly improve the code:
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#ProfileID", profileid);
DataTable dt = new DataTable();
da.Fill(dt);
var debtallout = new DebtAllOut() {
message = "Providing general message",
debtalldetail = new List<DebtAllDetail>()
};
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["RowID"] != DBNull.Value)
{
DebtSingleOut debtsingleout = new DebtSingleOut() {
debtsingleout.debtid = Convert.ToInt32(dt.Rows[i]["RowID"]);
}
debtallout.debtalldetail.Add(debtsingleout);
}
}

Related

Facing problem when looping through over list of objects

public class PriceDetail
{
public int ID{ get; set; }
public string Package { get; set; }
public string Currency { get; set; }
public int Price { get; set; }
public string PackageType { get; set; }
public List<string> Items { get; set; }
}
[WebMethod]
public static string GetCardDetail(string category)
{
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
List<PriceDetail> pricingCard = new List<PriceDetail>();
string query = "select [PricingID],[Package],[Currency],[Price],[PackageType] from [SeoDatabase].[dbo].[tbl_Pricing] where Category = #Category";
SqlConnection con = new SqlConnection(cs);
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("#Category", category);
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
PriceDetail priceDetail = new PriceDetail();
priceDetail.ID = Convert.ToInt16(rdr["PricingID"]);
priceDetail.Package = rdr["Package"].ToString();
priceDetail.Currency = rdr["Currency"].ToString();
priceDetail.Price = Convert.ToInt16(rdr["Price"]);
priceDetail.PackageType = rdr["PackageType"].ToString();
pricingCard.Add(priceDetail);
}
con.Close();
List<string> items = new List<string>();
string queryList = "select [Item] from [SeoDatabase].[dbo].[tbl_PricingItem] where PricingID = #pricingID";
int i = 0;
while(i < pricingCard.Count)
{
SqlCommand listCmd = new SqlCommand(queryList, con);
con.Open();
listCmd.Parameters.AddWithValue("#pricingID", pricingCard[i].ID);
SqlDataReader listReader = listCmd.ExecuteReader();
while (listReader.Read())
{
items.Add(listReader["Item"].ToString());
}
pricingCard[i].Items = items;
items.Clear();
con.Close();
i++;
}
string obj = JsonConvert.SerializeObject(pricingCard);
return obj;
}
Every thing is going good when i reached on second loop while(i < pricingCard.Count) in this loop on 0 index its working properly and assigning right value to pricingCard[i].Items = items; problem is that when it goes for second index(1) it assigns the value correctly but also change the value of first index(0) and when loop moves for third time it changes the value of index(0).Items and index(1).Items with index(2).Items values
Please help me to solve
The reason this is not behaving as you might expect is that items, being of type List<string>, is a reference type, not a value type. This a concept that you will need to understand well whilst developing with managed languages such as C#. MSDN - Reference and Value
Simplistically , what you are saying by pricingCard[i].Items = items; is that pricingCard[i].Items is now a reference to items. That means, at any given point after, an evaluation of pricingCard[i].Items will just "refer" you to items, therefore any changes to items will reflect on all reference you have made to it.
What you need to do, at the being of each loop, is to "re-instantiating" items with items = new List<string>(). This is to say: create a new instance of the list, and new instance to with the next iteration of pricingCard[i].Items will refer.
while(i < pricingCard.Count)
{
items = new List<string>();
// Do the rest of your process
}
Alternatively, add the items directly:
while (listReader.Read())
{
pricingCard[i].Items.Add(listReader["Item"].ToString());
}
P.S.
Rather than using:
int i = 0;
while(i < pricingCard.Count)
{
i++;
}
Try:
for (int i = 0; i < pricingCard.Count; i++)
{}

Class containing a List of a generically Typed Class

I have a generic class, JSTable, that takes a type RowType. I want to have a class that can contain many JSTables, each with a different RowType, so that I may do something like the Func<> in C# does, where it has many optional types. Is this only possible because there are many representations of Func<>? I want a limitless option, so that I could potentially declare a JSGridVM with hundreds of tables, or one table.
public class JSGridVM<?>//where ? is as many types as I want
{
public List<JSTable<?>> Tables { get; set; };
}
public class JSTable<RowType>
{
public JSTable() { }
public JSTable(List<RowType> rows, List<JSGridColumn> columns, bool allowEditingRows, bool allowDeletingRows, string updateURL, string deleteURL)
{
Rows = rows;
Columns = columns;
AllowEditingRows = allowEditingRows;
AllowDeletingRows = allowDeletingRows;
UpdateURL = updateURL;
DeleteURL = deleteURL;
}
public List<RowType> Rows { get; set; }
public List<JSGridColumn> Columns { get; set; }
public bool AllowEditingRows { get; set; }
public bool AllowDeletingRows { get; set; }
public string UpdateURL { get; set; }
public string DeleteURL { get; set; }
}
public class JSGridColumn
{
public string PropertyName { get; set; }
public ColumnType Type { get; set; }
}
public enum ColumnType
{
Text,
Hidden,
}
Then declare like
var jsGridVM = new JSGridVM<SomeClass1, SomeClass2, SomeClass3>();
OR
var jsGridVM = new JSGridVM<SomeClass1>();
You should declare generic type argument <RowType> not at class level, but at methods: AddTable and GetTable:
public class JSGridVM
{
private Dictionary<Type, object> Tables = new Dictionary<Type, object>();
public JSGridVM AddJSTable<RowType>()
{
Tables.Add(typeof(RowType), new JSTable<RowType>());
return this;
}
public JSTable<RowType> GetJSTable<RowType>()
{
Tables.TryGetValue(typeof(RowType), out object temp);
return (JSTable<RowType>)temp;
}
}
Usage:
var sample = new JSGridVM();
sample.AddJSTable<RowTypeA>().AddJSTable<RowTypeB>();
var test = a.GetJSTable<RowTypeA>();
You could roll your own class, but the .NET DataSet class might be what you are after. DataSet has been around for ages and is still pretty useful.
var ds = new DataSet();
var dataTable = new DataTable("DataTable");
var stringCol = new DataColumn("String Column", typeof(string));
var intCol = new DataColumn("Integer Column", typeof(int));
var decimalCol = new DataColumn("Decimal Column", typeof(decimal));
dataTable.Columns.AddRange(new [] {stringCol, intCol, decimalCol});
var newRow = new object[]
{
"String item",
1,
100.08m
};
dataTable.Rows.Add(newRow);
ds.Tables.Add(dataTable);
var row = ds.Tables["DataTable"].Rows[0];
var stringRowValue = row["String Column"];
var intRowValue = row["Integer Column"];
var decimalRowValue = row["Decimal Column"];
Console.WriteLine($"String value: {stringRowValue}\nInteger value: {intRowValue}\nDecimal Value: {decimalRowValue}");
var rowArr = new DataRow[ds.Tables["DataTable"].Rows.Count];
ds.Tables["DataTable"].Rows.CopyTo(rowArr, 0);
var list = rowArr.ToList();
foreach (DataRow rowitem in list)
{
Console.WriteLine($"\nFrom List: String value: {rowitem["String Column"]}\nInteger value: {rowitem["String Column"]}\nDecimal Value: {rowitem["String Column"]}");
}
Console.ReadKey();
Not sure what you are trying to accomplish, but this is already pretty robust. If you are trying to accomplish a specific use case by creating a generic class, then check out MSDN for more help.
Using Generics:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-type-parameters
Func:
https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx
Why not :
public class JSGridVM<JSTable>
{
public List<JSTable> Tables { get; set; };
}
public class JSTable<?>
{
}
var rowTypeAnimals = AnimalRowType();
var rowTypeBirds = BirdRowType();
var animalTable = new JSTable<AnimalRowType>(){rowTypeAnimals };
var birdTable = new JSTable<BirdRowType>(){rowTypeBirds };
var grid = new JSGridVM(){animalTable,birdTable};
Keep the row type generic for your table and your grid will always have the same JSTable type.

Add Remove Update List of class in C#

I'm working on this for more than a week and quit stressed currently,
Hope you guys can put me out of my misery.
I welcome If you can suggest overall different approach too. Okay here we go,
I'm on a learning curve and creating a small chat app using SignalR, MVC, JSON, jquery.
I have Chatter class which contain list of ChatMsg class (Msgs). As GetData() method shows below, I'm getting my classes populated from database to a list. As you can see list of Chatter contain some variables including list of ChatMsg. This will get any changes to Table ( new chat messages).
Up to here, this is working fine. [Add part]
[Serializable]
public class Chatter
{
public string Name { get; set; }
public bool Open { get; set; }
public DateTime LastMsg { get; set; }
public IEnumerable<ChatMsg> Msgs { get; set; }
}
[Serializable]
public class ChatMsg
{
public DateTime MsgCreated { get; set; }
public string MsgType { get; set; }
public string MsgBody { get; set; }
}
public List<Chatter> GetData()
{
Dictionary<string, List<ChatMsg>> dcm = new Dictionary<string, List<ChatMsg>>();
List<Chatter> lcm = new List<Chatter>();
using (var connection = new SqlConnection(_connString))
{
connection.Open();
using (var command = new SqlCommand(#"SELECT [Sender], [Receiver], [Body], [MessageCreated] FROM [dbo].[Chat] WHERE [Receiver] = #Name AND [Seen] = #Seen", connection))
{
command.Parameters.Add(new SqlParameter("#Name", "Fan"));//Test val
command.Parameters.Add(new SqlParameter("#Seen", "0"));//Test val
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
List<ChatMsg> cm = new List<ChatMsg>();
cm.Add(item: new ChatMsg { MsgCreated = Convert.ToDateTime(reader["MessageCreated"]), MsgType = "from", MsgBody = (string)reader["Body"] });
if (dcm.ContainsKey((string)reader["Sender"]))
{ dcm[(string)reader["Sender"]].Add(item: new ChatMsg { MsgCreated = Convert.ToDateTime(reader["MessageCreated"]), MsgType = "from", MsgBody = (string)reader["Body"] }); }
else { dcm.Add((string)reader["Sender"], cm); }
}
}
}
foreach (KeyValuePair<string, List<ChatMsg>> pair in dcm)
{
lcm.Add(item: new Chatter { Name = pair.Key, Open = true, LastMsg = DateTime.UtcNow, Msgs = pair.Value });
}
// Updateting [Seen] = 1 here
return lcm;
}
Now if this is a new instance I'm putting this list of Chatters to Session.
Each time when getData() gets new data I'd like to check my Session["ChatHistory"] and if Parent.Name exist I'd like to update Parent and Addrange to Msgs, if not ad new parent from getData() session list.
I'm strugling on following code.
public string receiveMessages()
{
if (Session["ChatHistory"] == null) Session["ChatHistory"] = new List<Chatter>();
List<Chatter> lc = (List<Chatter>)Session["ChatHistory"];
ChatRepository chatRepository = new ChatRepository();
List<Chatter> c = (List<Chatter>)chatRepository.getData();
//havent tested below
foreach (Chatter e in c)
{
var temp_lc = lc.Find(n => n.Name == e.Name);// Can we avoid linq?
if (temp_lc == null)
{
lc.Add(e);
}
else
{
// How to Addrange to Msgs?
}
}
var serializer = new JavaScriptSerializer();
var t = serializer.Serialize(lc);
return t;
}
How to Update list of class in list of class?
How to remove an item from list of class?
Thank you so much!
Consider using variable names like chatters and chatterHistory instead of c and lc. It makes it much easier to read.
Try rewriting your foreach in receiveMessages() like so:
foreach (Chatter e in c)
{
var temp_lc = lc.Where(x => x.Name == e.Name).SingleOrDefault();
if (temp_lc == null)
{
lc.Add(e);
}
else
{
temp_lc.Msgs = temp_lc.Msgs.Concat(e.Msgs).ToList();
}
}
If temp_lc exists, temp_lc.Msgs.Concat(e.Msgs).ToList() will concatenate the Msgs property with e.Msgs. ToList() converts it into a List<ChatMsg>, and then we can assign the whole thing back to temp_lc.Msgs.
That last step is important because Concat() does not mutate (change) the object it is called on - instead, it returns a new object that we then can assign back to temp_lc.Msgs.

cannot initialize type with a collection initializer because it does not implement ienumerable

I'm a fairly junior C# developer so please excuse me if this is very easy, but I am getting this error "invalid initializer member declarator" at this line of the code below:
foreach (DataRow p in data.Rows)
{
DBTrack top = new DBTrack()
/* ===> Error starts here */ {
track.TrackID = SQLDataHelper.GetGuid(dataReader, "TrackID");
track.TrackName = SQLDataHelper.GetString(dataReader, "TrackName");
track.ArtistName = SQLDataHelper.GetString(dataReader, "ArtistName");
track.AddedDate = SQLDataHelper.GetDateTime(dataReader, "AddedDate");
};
DBTrackData.Add(top);
}
Can someone explain what this means and how do I work around and achieve it to display the data?
Here's the full method for your inspection:
public static List<DBTrack> GetAllTracksFromReaderDB(IDataReader dataReader)
{
if (DBTrackData == null)
{
DBTrack track = new DBTrack();
System.Data.DataTable data = new System.Data.DataTable();
List<DBTrack> daa = new List<DBTrack>();
DBTrackData = new List<DBTrack>();
foreach (DataRow p in data.Rows)
{
DBTrack top = new DBTrack()
/* ===> Error starts here */ {
track.TrackID = SQLDataHelper.GetGuid(dataReader, "TrackID");
track.TrackName = SQLDataHelper.GetString(dataReader, "TrackName");
track.ArtistName = SQLDataHelper.GetString(dataReader, "ArtistName");
track.AddedDate = SQLDataHelper.GetDateTime(dataReader, "AddedDate");
};
DBTrackData.Add(top);
}
}
return DBTrackData;
}
EDIT:
public Guid TrackID { get; set; }
public string TrackName { get; set; }
public string ArtistName { get; set; }
public DateTime AddedDate { get; set; }
Any help would be great :) Thanks
Your syntax is invalid for member initialization. You cant instansiate top and try to fill track properties.
It should look like this:
DBTrack top = new DBTrack
{
TrackID = SQLDataHelper.GetGuid(dataReader, "TrackID"),
TrackName = SQLDataHelper.GetString(dataReader, "TrackName"),
ArtistName = SQLDataHelper.GetString(dataReader, "ArtistName"),
AddedDate = SQLDataHelper.GetDateTime(dataReader, "AddedDate")
};

How can I select items from my table in to a List<T>?

How can I get the results from my data reader into a List<String>?
Here is my code so far:
public List<string> Item_Getall()
{
List<string> data = new List<string>();
SqlCommand cmd = new SqlCommand("c_get_all_item",oo.conn);
cmd.CommandType = CommandType.StoredProcedure;
oo.conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
data.Add(rdr["item_name_id_pk"].ToString());
data.Add(rdr["item_name_arabic"].ToString());
data.Add(rdr["item_componant"].ToString());
data.Add(rdr["item_componant_arabic"].ToString());
data.Add(rdr["item_price"].ToString());
data.Add(rdr["item_image"].ToString());
data.Add(rdr["item_category_name_id_fk"].ToString());
}
oo.conn.Close();
return data;
}
You better use your custom type list instead of string and store your custom type object in list
List<YourCustomType> data = new List<YourCustomType>();
Custom type
public class YourCustom
{
public string ItemName {get; set;}
//Similarly all the properties.
}
Reading values from data Reader and adding in Custom Type List
while (rdr.Read())
{
data.Add(new YourCustom()
{
Id = rdr["item_name_id_pk"].ToString(),
Name = rdr["item_name_arabic"].ToString()
//Similarly all other properties could be set
}
}
I think you will want to create a custom class and return a list of this class:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
Reading would go as:
var data = new List<Item>();
while (rdr.Read())
{
data.Add(new Item()
{
Id = int.Parse(rdr["item_name_id_pk"]),
Name = rdr["item_name_arabic"].ToString()
}
}
return data;
Also, look into the using() statement which will make your code more robust in the eye of exceptions during database calls.
Using a DataAdapter and a custom type:
SqlCommand cmd = new SqlCommand("c_get_all_item",oo.conn);
cmd.CommandType = CommandType.StoredProcedure;
oo.conn.Open();
var adapter = new SqlDataAdapter(cmd);
DataTable dt;
adapter.Fill(dt);
oo.Close()
//Convert DataTable to a list of YourType
List<YourType> data = dt.AsEnumerable().Select(s=>
new YourType {
item_name_id_pk = s.Field<FieldDataType>("item_name_id_pk"),
item_name_arabic = s.Field<FieldDataType>("item_name_arabic"),
...
})
.ToList();
Your custom type would be like;
public class YourType
{
//Replace the DataType with correct datatype to match with FieldDataType
public DataType item_name_id_pk {get; set;}
public DataType item_name_arabic {get; set;}
...
}

Categories