Loop through Object Initializer - c#

How can I optimize the following piece of code?
IList<OrderItem> OrderItemsList = new List<OrderItem>();
while (orderItemsResult.Read())
{
new OrderItem()
{
ItemName = orderItemsResult.GetString("item_name"),
Price = orderItemsResult.GetFloat("price"),
Quantity = orderItemsResult.GetInt32("quantity")
},
}

Although a bit late to reply ,still I shall add my thoughts.
We can do without List<OrderItem> object.
The below code returns IEnumerable<OrderItem>
while (orderItemsResult.Read())
{
yield return new OrderItem()
{
ItemName = orderItemsResult.GetString("item_name"),
Price = orderItemsResult.GetFloat("price"),
Quantity = orderItemsResult.GetInt32("quantity")
};
}

As #crowcoder and #er-sho pointed out in the comments, you need to add the OrderItem to OrderItemsList:
IList<OrderItem> OrderItemsList = new List<OrderItem>();
while (orderItemsResult.Read())
{
var orderItem = new OrderItem()
{
ItemName = orderItemsResult.GetString("item_name"),
Price = orderItemsResult.GetFloat("price"),
Quantity = orderItemsResult.GetInt32("quantity")
};
// add to the list
OrderItemsList.Add(orderItem);
}

As in the accepted answer, you can implement it as an iterator function, but keep in mind that in case orderedItemsResult is an IDisposable such as IDataReader for reading from something like a database (the methods called on it appear that this is the case) to make sure to embed it in a try/finally or using block.
For example:
IEnumerable<OrderItem> GetOrders(string connectionString, string queryString)
{
IDbConnection connection = new MyDbConnection(connectionString);
IDbCommand command = null;
IDbReader orderedItemsResult = null;
try
{
connection.Open();
command = new MyCommand(queryString, connection);
orderedItemsResult = command.ExecuteReader();
while (orderItemsResult.Read())
{
yield return new OrderItem()
{
ItemName = orderItemsResult.GetString("item_name"),
Price = orderItemsResult.GetFloat("price"),
Quantity = orderItemsResult.GetInt32("quantity")
};
}
}
finally
{
orderItemsResult?.Dispose();
command?.Dispose();
connection.Dispose();
}
}
The IEnumerable returned which implements IDisposable as well executes the finally block whenever it is disposed (for example, when a foreach is done with it)

Related

How to convert Linq result to viewmodel

while filling a combobx, I need to convert a Linq-result to a viewmodel.
Actually, I query the records and then I fill a list of the viewmodel in a loop, but that seems to be a bit strange:
public static IEnumerable<ComboBoxActivities> GetActivitySelectList()
{
using(ApplicationDbContext db = new ApplicationDbContext())
{
var result = from activity in db.Activities
where activity.Available
select new
{
ActivityId = activity.Id,
ActivityName = activity.ActivityName,
Available = activity.Available
};
List<ComboBoxActivities> list = new List<ComboBoxActivities>();
foreach(var res in result)
{
ComboBoxActivities listItem = new ComboBoxActivities()
{
ActivityId= res.ActivityId,
ActivityName= res.ActivityName,
Available= res.Available
};
list.Add(listItem);
}
return list;
}
}
Is this really the right way?
I also tried:
var result = from activity in db.Activities
where activity.Available
select new ComboBoxActivities()
{
ActivityId = activity.Id,
ActivityName = activity.ActivityName,
Available = activity.Available
};
But then my razorview crashes with the message that direct binding to a quers (DbSet, DbQuery...) is not supported.
You can convert the IEnumerable<T> to a List<T> by using ToList()
public static List<ComboBoxActivities> GetActivitySelectList()
{
using(ApplicationDbContext db = new ApplicationDbContext())
{
var result = from activity in db.Activities
where activity.Available
select new ComboBoxActivities()
{
ActivityId = activity.Id,
ActivityName = activity.ActivityName,
Available = activity.Available
};
return result.ToList();
}
}
As for loading a ComboBox from a table query, ComboBox has a DataSource property which you can assign the List to.

C# Web API loop posts one value only

I read my rows from SQL into and object and then would like to post them using the code below to the web api. One row is posted, however the other 99 rows are not. Is there something missing in my code for the for each loop?
Code Below …
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
List<ProductSQL> myObjectList = new List<ProductSQL>();
var reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
ProductSQL myObject = new ProductSQL();
myObject.sku = reader["sku"].ToString();
myObject.title = reader["title"].ToString();
myObject.description = reader["description"].ToString();
myObjectList.Add(myObject);
}
}
var JsonResult = JsonConvert.SerializeObject(myObjectList);
Console.WriteLine(myObjectList);
Console.WriteLine(JsonResult);
/* Program Initialization Now need to see why multiple articles are not*/
Console.WriteLine("Post Articles To API");
HttpResponseMessage response2;
Product NewProduct = new Product();
foreach (ProductSQL product in myObjectList.ToList())
{
NewProduct.sku = product.sku;
NewProduct.title = product.title;
NewProduct.description = product.description;
}
/* Mapping that needs to be autmated between models , Product.cs and ProductSQL.cs */
response2 = await client.PostAsJsonAsync("sites/1/products.json",NewProduct);
if (response2.IsSuccessStatusCode)
{
Uri Product = response2.Headers.Location;
Console.WriteLine(response2);
}
You post only one product because PostAsJsonAsync is executed outside the foreach block!
Putting the code inside foreach block should solve your problem.
foreach (ProductSQL product in myObjectList)
{
Product newProduct = new Product {
sku = product.sku,
title = product.title,
description = product.description,
}
/* Mapping that needs to be autmated between models , Product.cs and ProductSQL.cs */
response2 = await client.PostAsJsonAsync("sites/1/products.json", product);
if (response2.IsSuccessStatusCode)
{
Uri productUri = response2.Headers.Location;
Console.WriteLine(response2);
}
}
OTHER THINGS:
myObjectList is already a List, so you don't need the .ToList()
What is the use of var JsonResult = JsonConvert.SerializeObject(myObjectList);?
Little thing about naming convention: NewProduct would be better if named newProduct

Converting types C#

I am having difficulty with the following method:
public override List<Team> Search(Dictionary<string, string> prms,
int pageSize, int page, out int results)
{
List<Team> t = null;
//Team t = null;
var tresults = new List<Team>();
using (SqlConnection conn = DB.GetSqlConnection())
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = #"SearchForTeam";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
foreach (var key in prms.Keys)
{
cmd.Parameters.Add(key, prms[key]);
}
SqlDataReader reader
= cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
var temp = Load(reader);
if (t == null)
{
t = temp;
}
else
{
t.CityHistory.Add(temp.CityHistory[0]);
}
}
}
}
results = 0;
return t;
}
The error lies mainly with the if and else statement where the temp in the if block is claiming that it "cannot implicitly convert type DataLayer.Team to System.Collections.GenericList"
EDIT:
Here is my load method:
public Team Load(SqlDataReader reader)
{
var team = new Team()
{
TeamID = Int32.Parse(reader["TeamID"].ToString()),
TeamName = reader["TeamName"].ToString()
};
team.CityHistory.Add(
new TeamCity(
Int32.Parse(reader["TeamCitiesID"].ToString()),
team.TeamID,
Int32.Parse(reader["CityID"].ToString()),
reader["CityName"].ToString(),
Int32.Parse(reader["YearStart"].ToString()),
Int32.Parse(reader["YearEnd"].ToString())
)
);
return team;
}
t is defined as List<Team>, yet you later say t.CityHistory. CityHistory is clearly not a property of List<>. I'd guess it's a property of Team, but since you never show us that we can't say.
Show us the definition of Team and the method signature of Load() and perhaps we can give an answer.
UPDATE (from OP's update)
Now, I'm going to assume that you are getting multiple rows, one for each City, with the team info repeating. So, which you want is:
var temp = Load(reader);
// remove t definition above
var t = tresults.FirstOrDefault(team=> team.TeamId == temp.TeamId);
if (t == null)
{
t = temp;
tresults.Add(t);
}
else
t.CityHistory.Add(temp.CityHistory[0]);
(Updated again, based on Steve's comment)
You have to wrap temp into a List first to assign it to t:
if (t == null) {
t = new List<Team>() { temp }
} else {
t.add(temp);
}
VERY LONG COMMENT:
Consider the following refactoring of your method:
private IEnumerable<Team> LoadTeams()
{
using (SqlConnection conn = DB.GetSqlConnection())
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = #"SearchForTeam";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
foreach (var key in prms.Keys)
{
cmd.Parameters.Add(key, prms[key]);
}
SqlDataReader reader
= cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
yield return Load(reader);
}
}
}
}
public override List<Team> Search(Dictionary<string, string> prms,
int pageSize, int page, out int results)
{
List<Team> searchResult = new List<Team>;
//Team t = null;
var tresults = new List<Team>();
foreach(Team team in LoadTeams())
{
if (team .....)
searchResult.Add(team);
}
results = 0;
return searchResult;
}
Take into account this NEEDED initialization:
List<Team> searchResult = new List<Team>;
And ask yourself: What should the following excerpt do? :
if (team .....)
searchResult.Add(team);
P.S.: Also the line
results = 0;
should probably look like:
results = searchResult.Count;
I'm having to guess a little here, but I assume that your Load() method is returning a data type 'DataLayer.Team', which sounds like its one Team, and you're trying to assign it to 't', which is a list of teams.
Try:
t.Add(temp)
or
t.Add(temp as Team).
It doesn't help that you're using 'var' declarations all the time.

Add columns to dataset to be used as XML parent nodes

I'm trying to format XML from a MySQL query to emulate what a client frontend is expecting for input. I have no control over what the client requires, so I have to match what I've gotten from Wireshark captures. I am not married to the idea of adding columns to the dataset to do this, and I can probably just do a search and replace for the additions to the XML, however, I have a large number of very similar, yet different queries & outputs to write, and I'd prefer to do something that scales well. Unfortunately it'll be throw away code because when I write the new front end client for this, we won't be tracking a lot of the data the current legacy system does like client IP address, or the supposedly unique "ActionID" both of which you'll see referenced below, nor will I have to do anything with XML, it'll all be MySQL driven queries.
My output should be in a form like this:
<PCBDatabaseReply>
<SearchResult>
<SBE_PCB_Data PCBID="53">
<Termination ActionID="97DF" User="UName:192.168.255.255" Date="2012-09-26T13:15:51" PCBID="53">
<Reason>Other</Reason>
</Termination>
</SBE_PCB_Data>
</SearchResult>
</PCBDatabaseReply>
The results from my query look like this:
EventType User Date PCBID Reason
Termination UName 2012-09-26T13:15:51 53 Other
My output XML currently looks like this:
<PCBDatabaseReply>
<Termination User="UName" Date="2012-09-26T13:15:51" PCBID="53">
<EventType>Termination</EventType>
<Reason>Other</Reason>
</Termination>
</PCBDatabaseReply>
Using this code:
string mysqlConnection = "server=server;\ndatabase=database;\npassword=password;\nUser ID=user;";
MySqlConnection connection = new MySqlConnection(mysqlConnection);
connection.Open();
string command = "SELECT eventtypes.EventType, events.User, DATE_FORMAT(events.DateTime,'%Y-%m-%dT%T') AS Date, pcbid.PCBID, getReasons.ItemValue AS Reason " +
"FROM events " +
"INNER JOIN pcbid ON events.PCBID = pcbid.PCBID " +
"INNER JOIN eventtypes " +
"ON events.EventType_ID = eventtypes.EventType_ID " +
"LEFT JOIN getReasons " +
"ON getReasons.Event_ID = events.Event_ID " +
"WHERE eventtypes.EventType = 'termination'";
//create fake "ActionID"
var random = new Random();
string ActionID = String.Format("{0}\"{1:X4}\"", "ActionID=", random.Next(0xffff));
MySqlDataAdapter adapter = new MySqlDataAdapter(command, connection);
DataSet dataSet = new DataSet();
adapter.Fill(dataSet);
//change upper level node name to what's expected in client-speak
dataSet.DataSetName = "PCBDatabaseReply";
//change first child node name to client-speak eventType
dataSet.Tables[0].TableName = dataSet.Tables[0].Rows[0][0].ToString();
StringWriter writer = new StringWriter();
var ds1 = dataSet.Tables[0];
DataColumn dcEventType = ds1.Columns[0];
DataColumn dcUser = ds1.Columns[1];
DataColumn dcDate = ds1.Columns[2];
DataColumn dcPCBID = ds1.Columns[3];
dcEventType.ColumnMapping = MappingType.Element;
dcUser.ColumnMapping = MappingType.Attribute;
dcDate.ColumnMapping = MappingType.Attribute;
dcPCBID.ColumnMapping = MappingType.Attribute;
dataSet.Tables[0].WriteXml(writer, true);
Console.WriteLine(writer.ToString());
I need to inject several things
At the top beneath <PCBDatabaseReply>:
<SearchResult>
<SBE_PCB_Data PCBID="53">
In the Termination tag: (from the fake ActionID in the code)
ActionID="0xnnnn" & append ":192.168.255.255" to the end of the user name
And then close with the appropriate tags:
</SBE_PCB_Data>
</SearchResult>
I have tried adding a dummy column for the "SBE_PCB_Data" tag, which didn't work.
DataColumn dcSBE_PCB_Data = new DataColumn("SBE_PCB_Data", System.Type.GetType("System.String"), "SBE_PCB_Data", MappingType.Element);
dcSBE_PCB_Data.DefaultValue = "SBE_PCB_Data";
//add to the dataset
dataSet.Tables[0].Columns.Add(dcSBE_PCB_Data);
//move it to the zeroth position
dcSBE_PCB_Data.SetOrdinal(0);
This just makes it show up as:
<SBE_PCB_Data>SBE_PCB_Data</SBE_PCB_Data>
I need it to wrap around the rest of the XML as an ancestor node.
How best to inject the XML I need into the results?
EDIT: refactored according to excellent example below
**EDIT: updated with final code
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Xml.Linq;
using MySql.Data.MySqlClient;
namespace TerminationResults
{
public class SearchResult
{
//all possible event detail tags (test items are excluded)
public string EventType { get; set; }
public string User { get; set; }
public string Date { get; set; }
public string PCBID { get; set; }
public string EAReason { get; set; }
public string ETReason { get; set; }
public string Notes { get; set; }
public string Reason { get; set; }
public string SBEJobNumber { get; set; }
public string SBEModelNumber { get; set; }
public string SBEPN { get; set; }
public string SBESerialNumber { get; set; }
//create fake IP address since we no longer track it
public string UserAndIP
{
get { return String.Format("{0}:192.168.255.255", User); }
set {}
}
//create fake actionID since the originals weren't inserted into the database because they weren't unique.
public string ActionId
{
get { return String.Format("{0:X4}", new Random().Next(0xffff)); }
set {}
}
}
internal class Program
{
private static void Main(string[] args)
{
var searchResults = GetSearchResults();
var xml = TransformList(searchResults);
Console.WriteLine(xml);
Console.ReadLine();
}
public static IEnumerable<SearchResult> GetSearchResults()
{
List<SearchResult> searchResults = new List<SearchResult>();
try
{
const string mysqlConnection = #"server=server;
database=database;
password=password;
User ID=username;";
MySqlConnection conn = new MySqlConnection(mysqlConnection);
conn.Open();
using (conn)
{
string cmd = #"SELECT eventtypes.EventType, events.User,
DATE_FORMAT(events.DateTime,'%Y-%m-%dT%T') AS Date,
pcbid.PCBID,
getEAReasons.ItemValue AS EAReason,
getETReasons.ItemValue AS ETReason,
getReasons.ItemValue AS Reason,
getNotes.ItemValue AS Notes,
getSBEJobNumbers.ItemValue AS SBEJobNumber,
getSBEModelNumbers.ItemValue AS SBEModelNumber,
getSBEPNs.ItemValue as SBEPN,
getSBESerialNumbers.ItemValue as SBESerialNumber
FROM events
INNER JOIN pcbid ON events.PCBID = pcbid.PCBID
INNER JOIN eventtypes
ON events.EventType_ID = eventtypes.EventType_ID
LEFT JOIN getEAReasons
ON getEAReasons.Event_ID = events.Event_ID
LEFT JOIN getETReasons
ON getETReasons.Event_ID = events.Event_ID
LEFT JOIN getReasons
ON getReasons.Event_ID = events.Event_ID
LEFT JOIN getNotes
ON getNotes.Event_ID = events.Event_ID
LEFT JOIN getSBEJobNumbers
ON getSBEJobNumbers.Event_ID = events.Event_ID
LEFT JOIN getSBEModelNumbers
ON getSBEModelNumbers.Event_ID = events.Event_ID
LEFT JOIN getSBEPNs
ON getSBEPNs.Event_ID = events.Event_ID
LEFT JOIN getSBESerialNumbers
ON getSBESerialNumbers.Event_ID = events.Event_ID
WHERE eventtypes.EventType = 'termination'";
try
{
using (MySqlDataAdapter adapter = new MySqlDataAdapter(cmd, conn))
{
DataSet dataSet = new DataSet();
adapter.Fill(dataSet);
DataTable ds = dataSet.Tables[0];
for (int row = 0; row < ds.Rows.Count; row++ )
{
SearchResult result = new SearchResult()
{
EventType = ds.Rows[row]["EventType"].ToString(),
User = ds.Rows[row]["User"].ToString(),
Date = ds.Rows[row]["Date"].ToString(),
PCBID = ds.Rows[row]["PCBID"].ToString(),
EAReason = ds.Rows[row]["EAReason"].ToString().Any() ? ds.Rows[row]["EAReason"].ToString() : null,
ETReason = ds.Rows[row]["ETReason"].ToString().Any() ? ds.Rows[row]["ETReason"].ToString() : null,
Notes = ds.Rows[row]["Notes"].ToString().Any() ? ds.Rows[row]["Notes"].ToString() : null,
Reason = ds.Rows[row]["Reason"].ToString().Any() ? ds.Rows[row]["Reason"].ToString() : null,
SBEJobNumber = ds.Rows[row]["SBEJobNumber"].ToString().Any() ? ds.Rows[row]["SBEJobNumber"].ToString() : null,
SBEModelNumber = ds.Rows[row]["SBEModelNumber"].ToString().Any() ? ds.Rows[row]["SBEModelNumber"].ToString() : null,
SBEPN = ds.Rows[row]["SBEPN"].ToString().Any() ? ds.Rows[row]["SBEPN"].ToString() : null,
SBESerialNumber = ds.Rows[row]["SBESerialNumber"].ToString().Any() ? ds.Rows[row]["SBESerialNumber"].ToString() : null
};
searchResults.Add(result);
}
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex);
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return searchResults;
}
public static XElement TransformSearchResult (SearchResult result)
{
return new XElement("SBE_PCB_Data",
new XAttribute("PCBID", result.PCBID),
new XElement(result.EventType,
new XAttribute("ActionID", result.ActionId),
new XAttribute("User", result.UserAndIP),
new XAttribute("Date", result.Date),
new XAttribute("PCBID", result.PCBID),
result.EAReason == null ? null : new XElement("EAReason", result.EAReason),
result.ETReason == null ? null : new XElement("ETReason", result.ETReason),
result.Reason == null ? null : new XElement("Reason", result.Reason),
result.Notes == null ? null : new XElement("Note", result.Notes),
result.SBEJobNumber == null ? null : new XElement("SBEJobNumber", result.SBEJobNumber),
result.SBEModelNumber == null ? null : new XElement("SBEModelNumber", result.SBEModelNumber),
result.SBEPN == null ? null : new XElement("SBEPN", result.SBEPN),
result.SBESerialNumber == null ? null : new XElement("SBESerialNumber", result.SBESerialNumber)
)
);
}
public static XElement TransformList (IEnumerable<SearchResult> listOfResults)
{
return new XElement("PCBDatabaseReply",
new XElement("SearchResult",
from r in listOfResults
select TransformSearchResult(r)));
}
}
}
Had to do some tweaking to get this to run, but the concept is sound, and I like that it's extensible. It doesn't quite give the right output yet, but I can tweak that as well.
Ok, Let's refactor this.
Lets not try and do this directly from your dataset, you are trying to do to many things in your method here, it's messy hard to maintain and very hard to unit test.
The first thing we should do is create a SearchResult class that we can work with more easily, this is also a convenient place to put in our Business rules (Ip added to User and random ActionId) it also means that we can easily mock up data into this class without having to hit the database, we can then test our transform logic as a unit test, not an integration test (which are slower, and have more dependencies)
public class SearchResult
{
public string EventType {get ;set;}
public string User {get ; set;}
public DateTime Date {get;set;}
public int PCBID {get;set;}
public string Reason {get;set;}
public string UserAndIP
{
get
{
return String.Format("{0}:192.168.255.255",User);
}
}
public string ActionId
{
get
{
return String.Format("{0:X4}", new Random().Next(0xffff));
}
}
}
So lets rewrite the query to now populate a list of SearchResult's instead of a dataset
public IEnumerable<SearchResult> GetSearchResults()
{
using(var conn = GetYourConnection())
{
conn.open();
using(var cmd = conn.CreateCommand())
{
cmd.CommandText = GetYourQueryString();
using(var reader = cmd.ExecuteReader())
{
while(reader.Read())
{
var result = new SearchResult
{
.... populate from reader...
}
yield return result;
}
}
}
}
}
So now that we have a SearchResult class and a query method that gives us a list of them, lets transform that to your required XML.
Firstly, I'll make some assumtions that are not 100% clear from your question. (if these are not correct, it will be easy enough to modify)
I'll assume that we are creating a search result tag for each search
result returned from our query. And that these will be contained in
the PCBDatabaseReply tag.
The xml tag "Termination" is the value of the Event Type, so I'll
assume that tag should be the EventType value.
Lets use Linq to XML to create the XML from the list of SearchResults
Firstly We'll create a method that transforms individual SearchResults (the contents of the SearchResult tag)
public XElement TransformSearchResult(SearchResult result)
{
return new XElement("SearchResult",
new XElement("SBE_PCB_Data", new XAttribute("PCBID", result.PCBID)),
new XElement(result.EventType,
new XAttribute("ActionID", result.ActionId),
new XAttribute("User", result.UserAndIP),
new XAttribute("Date", result.Date),
new XAttribute("PCBID", result.PCBID)),
new XElement("Reason", result.Reason));
}
Secondly we'll create the method to transform the list
public XElement TransformList(IEnumerable<SearchResult> listOfResults)
{
return new XElement("PCBDatabaseReply",
from r in listOfResults
select TransformSearchResult(r));
}
Now our main calling method simply becomes...
var searchResults = GetSearchResults();
var xml = TransformList(searchResults);

Adding properties of an Object together in a collection

I have an app that creates ContactList Objects and adds them to a Dictionary collection. My ContactList objects have a property called AggLabels which is a collection of AggregatedLabel objects containg Name and Count properties. What I am trying to do is change the "else" case of my code snippet so that before adding a new AggregatedLabel it will check whether the AggLabel.Name exists in the AggregatedLabel collection and if this is true it will not add the AggLabel.Name again. Instead it will add the value of AggLabel.Count (type int) to the existing AggregatedLabel object. So for an existing object, if the first Count value was 3 and the second value is 2 then the new Count value should be 5. In simple terms I want to have unique AggLabel Names and add together the Counts where the Names are the same. Hope that makes sense - would appreciate any help. Thanks!
Code snippet
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
//contactList.AggLabels = new ObservableCollection<AggregatedLabel>() { new AggregatedLabel() { Name = dr["LABEL_NAME"].ToString(), Count = Convert.ToInt32(dr["LABEL_COUNT"])}};
contactList.AggLabels = new ObservableCollection<AggregatedLabel>()
{
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
ContactList contactList = myContactDictionary[id];
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
There are two possible solutions I can think of:
1) Use a dictionary instead of the collection of aggregated labels the same way you do it for the contact dictionary. When yout use the name as key and the count as value, you can use the ContainsKey-Method to check whether the label already exists.
contactList.AggLabels = new Dictionary<string, int>();
...
else
{
ContactList contactList = myContactDictionary[id];
if (contactList.AggLabels.ContainsKey(dr["LABEL_NAME"].ToString()))
{
contactList.AggLabels[dr["LABEL_NAME"].ToString()] += Convert.ToInt32(dr["LABEL_COUNT"]);
}
else
{
contactList.AggLabels.Add(dr["LABEL_NAME"].ToString(), Convert.ToInt32(dr["LABEL_COUNT"]));
}
}
2) I you need to use the AggreagteLabel object you can use a loop to search throug all labels.
else
{
bool flagAggLabelFound = false;
ContactList contactList = myContactDictionary[id];
foreach(AggregateLabel aggLabel in contactList.AggLabels)
{
if(aggLabel.Name == dr["LABEL_NAME"].ToString())
{
aggLabel.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
flagAggLabelFound = true;
break;
}
}
if (!flagAggLabelFound)
{
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
I hope this helps.
I would try this:
ContactList contactList = myContactDictionary[id];
AggregateLabel existing = contactList.AggLabels.FirstOrDefault(
l => l.Name == dr["LABEL_NAME"].ToString()
);
if (existing == null) { contactList.AggLabels.Add(
new AggregatedLabel() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
else { existing.Count += Convert.ToInt32(dr["LABEL_COUNT"]); }
#extract these Aggregated Labels and put them in a separate Observable collection:
1) If you a Dictionary for storing the labels in the contact list, this should work:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>();
foreach (KeyValuePair<string, int> aggLabel in aggregateLabels)
{
copyOfAggregateLabels.Add(
new AggregatedLabel() {
Name = aggLabel.Key,
Count = aggLabel.Value
}
);
}
2) If you use an ObservableCollection of AggregateLabels, you get an AggregateLable instead of a KeyValuePair in the loop. The rest works the same way.
First I thought of something like:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>(aggregateLables);
But this way you get a new ObservableCollection, but the labels stored in the new collection are still referring to the same objects as the ones in the collection you copy.

Categories

Resources