I am using Visual Studio 2012 and C#. I have a problem: I want to collect all results of a SQL query into dictionary.
This is my code:
Dictionary<int,List<string>> dic = new Dictionary<int, List<string>>();
string query = "select request_number, service_category ,service_type from enugro.enugro_service_requests_info;";
MySqlConnection connec = new MySqlConnection(strcon);
connec.Open();
MySqlCommand cmd = new MySqlCommand(query,connec);
MySqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
dic.Add((int)reader["request_number"], { reader["service_category"], reader["service_type"] });
}
// display result
foreach(var disp in dic)
{
MessageBox.Show(disp.Key.ToString()+"= "+disp.Value.ToString());
}
As you can see my SQL query returns 3 columns to be retrieved and to store into dictionary. Could you help me?
Since the type of the dictionary values is List<string>, then you need to create a new list for each row and add it to the dictionary like this:
dic
.Add(
(int)reader["request_number"],
new List<string>
{
reader["service_category"].ToString(),
reader["service_type"].ToString()
});
Consider creating a class to hold the information that you want from each row and use it as the type for the dictionary values. Such class would look something like this:
public class MyValue
{
public string ServiceCategory {get;set;}
public string ServiceType {get;set;}
}
Then you can have your dictionary be of type Dictionary<int, MyValue> which will allow you to do this:
dic
.Add(
(int)reader["request_number"],
new MyValue
{
ServiceCategory = reader["service_category"].ToString(),
ServiceType = reader["service_type"].ToString()
});
Why would you do that? You can create DTO (data transfer object) with properties according to column names in database, and bind query result to it. Then you can return list of DTO objects. It would be better solution, then complicating with dictionary.
Related
I have created a nested dictionary with the following:
Dictionary<DateTime, Dictionary<string, string>> dateDict =
new Dictionary<DateTime, Dictionary<string, string>>();
I then enter values to this dictionary using the following:
while (reader.Read())
{
DateTime date = DateTime.Parse(reader["Event_Date"].ToString());
string name = reader["Event_Name"].ToString();
string guid = reader["Event_GUID"].ToString();
dateDict.Add(date, new Dictionary<string, string>());
dateDict[date].Add(name, guid);
}
My question is how do I correctly pull the variables back out from the nested dictionary?
I have this loop running to pull values out and assign them to DateTimePickers and TextFields:
for (int i = 0; i < dateDict.Count; i++)
{
DateTime keyVar = dateDict.ElementAt(i).Key;
eventDateBoxes[i].Value = keyVar;
eventTextBoxes[i].Text = dateDict[keyVar[]];
}
The eventTextBoxes part is where im getting stuck on how to pull the value from the nested dictionary, hence why that part of the code is wrong/incomplete.
I can't use tuples as I am using .NET lower than 4 and can't seem to wrap my head around making a custom class to act as its own tuple or multidictionary.
It sounds like you don't need a Dictionary<DateTime, Dictionary<string, string>> since you have only one item inside your inner dictionary, you need a Dictionary<DateTime, Dictionary<string, Event>> where Event is a class that holds you event data. Something like:
public class Event
{
public string Name {get; set;}
public string Guid {get; set;} // you could actually use the GUID type here!
}
Then you'd populate it like:
while (reader.Read())
{
DateTime date = DateTime.Parse(reader["Event_Date"].ToString());
string name = reader["Event_Name"].ToString();
string guid = reader["Event_GUID"].ToString();
dateDict.Add(date, new Event() { Name = name, Guid = guid };
}
Then when you get an item from your dictionary by key:
var item = dateDict[someKey];
You can get your name and guid back:
var name = item.Name;
var guid = item.guid;
Additionally, since you are iterating through your dictionary by numerical index rather than by key, it seems likely that you probably don't need a dictionary at all. Maybe all you need to do is add a Date property to your Event and just have an List<Event>.
I would use a foreach or a LINQ query. But it's not clear what you want as DateTimePicker.Text:
List<DateTimePicker> eventDateBoxes = dateDict
.Select(kv => new{
Date = kv.Key,
EventName = kv.Value["Event_Name"],
EventGuid = kv.Value["Event_GUID"],
})
.Select(x => new DateTimePicker{ Value = x.Date, Text = x.EventName })
.ToList();
This is the basic outline of what you would do:
foreach (var element in dateDict)
{
eventDateBoxes[i].Value = element.Key;
foreach (var subElement in element.Value)
{
eventTextBoxes[i].Text = subElement.Value;
}
}
As others point out in the comment, there can be no one-to-one relationship between the elements in the outer dictionary and the text boxes as there can (potentially) be multiple entries in the sub-element.
I have two dictionary one composed by:
1) <Id, Name>
This dictionaryis sorted by "Name"
Another dictionary composed by:
2) <Id, ListOfValues>
This dictionary`is not sorted.
I have to sort the second dictionary in the same order of the first, i can use Id as common point, how i can do this?
How i can sort the second dictionary
String json = data as string;
var rawData = JsonConvert.DeserializeObject<List<SectionItem>>(json);
/* New dictionary used to order item for name */
Dictionary<string, string> dataToOrder = new Dictionary<string, string>();
var name ="";
/* Getting data in "local language" */
var local_lang = ConfigurationContext.CurrentLocale;
/* In dataToOrder I insert name and Id*/
foreach (SectionItem si in rawData)
{
name = si.Entities[local_lang].Name;
dataToOrder.Add(name, si.Id);
}
/* List with ordered data by name*/
var orderedData = dataToOrder.OrderBy(kvp => kvp.Key).ToList();
Now I have to order each element of rawdata in the same order of orderedData , how i can do this ?
public class SectionItem
{
public string Id;
public Dictionary<string, EntityGroup> Entities;
}
Assuming you want to sort SecondDictionary based on Key of a dataToOrder, you could do this.
Look for an index of seconddiction Key in the first dictionary and use for Ordering the dictionary..
var ids = dataToOrder.Keys.ToList();
SecondDictionary.OrderBy(x=> ids.Contain(x.Key)? ids.IndexOf(x.Key) : int.MaxValue);
I am trying to iterate a file reading data line by line. After reading I would like to store in Dictionary. keys are unique but values are having list of values for a key(may be 50 values per key). But while iterating keys comes randomly.How do I create a newlist for each key and store the value in the corresponding List when next time same key comes...how to store all those new keys and corresponding lists in dictionary.Please me on this..
Here is explanation of my code ..
Dictionary<String,List<PropertyCollection>> dict = new Dictionary<String,List<PropertyCollection>>();
List<String> list1 = new List<String>();
//Here I am iterating the each record and getting the type and id
for (i=1;i<datarr.length -1;i++){
String type = datarr[3].Trim();
String id = datarr[1].Trim();
//here I am checking the key in map adding
if(dict.ContainsKey(type)){
//I need help here if the key is not there create a new record with key as "type" and values as "id"s. All the values of same type should add in a list.If any new type comes in iteration it should add as new entry and having key and values are Ids in a list format.
I stuck here ..
}
}
I don't know how many "types " are there in that file .So I need to build the List dynamically.
Please help .
this is a pretty common scenario when working with a Dictionary whose value is a collection. You just need to make sure that the collection is initialized for that key before trying to add anything to it:
//using Dictionary<int, List<string>>
for(int i in ...)
{
if (!dict.ContainsKey(i))
dict[i] = new List<string>();
dict[i].Add("hello");
}
Now every new key coming in will get a fresh List<string>
Class to Build your data:
class DataBuilder
{
public Dictionary<string, List<string>> Data { get; } = new Dictionary<string, List<string>>();
public void Add(string key, string dataVal)
{
if (!Data.ContainsKey(key))
{
Data.Add(key, new BaseList<string>());
}
Data[key].Add(dataVal);
}
}
This is how you can use above class to build data while you are reading file(s):
static void Main(string[] args)
{
var builder = new DataBuilder();
builder.Add("Key1", "Test Data 1");
builder.Add("Key1", "Test Data 2");
builder.Add("Key2", "Test Data 3");
builder.Add("Key1", "Test Data 4");
}
Update as per your query: Change your code to this:
private void Process()
{
Dictionary<String, List<string>> dict = new Dictionary<String, List<string>>();
for (int i = 0; i < numOfRec - 1; i++)
{
//Code to Read record at index i into dataarr.
String type = datarr[3].Trim();
String id = datarr[1].Trim();
if (!dict.ContainsKey(type))
{
dict.Add(type, new BaseList<string>());
}
dict[type].Add(id);
}
}
}
I wanna convert an object Array called "list" into a string Array called "test".
Attached the code.
The Problem is, the function is returning "System.Collections.Generic.Dic..." and not the strings in SQL database.
Thanks..
Code:
public string[] ListMethod(string command)
{
MySqlCommand comm = new MySqlCommand(command, conn);
MySqlDataReader commreader;
commreader = comm.ExecuteReader();
var list = new List<IDictionary<string, object>>();
while (commreader.Read())
{
var record = new Dictionary<string, object>();
for (int i = 0; i < commreader.FieldCount; i++)
{
var key = commreader.GetName(i);
var value = commreader[i];
record.Add(key, value);
}
list.Add(record);
}
string[] test = ((IEnumerable)list).Cast<object>().Select(x => x.ToString()).ToArray();
return test;
}
Lets look at your LINQ Query:
string[] test = ((IEnumerable)list).Cast<object>().Select(x => x.ToString()).ToArray();
What you are saying to the compiler here is:
Cast all objects in the list of dictionaries to object, and then execute to ToString() method of each object (which by default always prints the name of the class) and set it to an array (The cast do IEnumerable is redundant since List implements that interface anyway.
What you actually need to do is:
var test = list.Select(x => x.Values.ToString()).ToArray();
assuming all your values in the IDictionary are actually strings, this will fetch them for you.
At the moment, I'm creating a new method for each mysql query with parameters I want to get performed.
An example:
public DataTable RetreiveAllLinks(int id, int categoryid)
{
const string request =
#"
SELECT *
FROM links
WHERE id=?id,categoryid=?categoryid
ORDER by id DESC
";
using (var query = new MySqlCommand(request))
{
query.Parameters.AddWithValue("?id", id);
query.Parameters.AddWithValue("?categoryid", categoryid);
return _connection.RetreiveData(query);
}
}
This is really getting on my nerves, because I always end up with 10-30 queries, when two queries can do it for me, a simple method for retrieving non-parameter query, and a method for parameters. For example
public DataTable NonParameterCommand(string r)
{
var request = r;
using (var query = new MySqlCommand(request))
{
return _connection.RetreiveData(query);
}
}
What I want to do, is some regex'ing, where i would say e.g.
var pPattern = "^[\\?][\\w]";
and then a method with request and a list as parameters, and the list should be in the same order as the request parameters. So if the request is
`"SELECT * FROM test WHERE id=?id,categoryid=?categoryid"`
then my list would look like
var _dictionary = new Dictionary<string, string>();
_dictionary.Add(_parameter, _value);
and my method
ParameterCommand(string r, Dictionary dic)
but how exactly?
If you are using a dictionary, then the key would already be the parameter name. Why parse the query to extract them?
You could do:
public DataTable CommandWithParams(string sql, Dictionary<string, object> parameters)
{
using (var query = new MySqlCommand(sql))
{
foreach (var param in parameters)
{
query.Parameters.AddWithValue(param.Key, param.Value);
}
return _connection.RetreiveData(query);
}
}
Calling it:
var parameters = new Dictionary<string, object>()
{
{ "?param1", value1 },
{ "?param2", value2 }
};
var result = CommandWithParams(query, parameters);
But maybe you'd like to use a List instead of a Dictionary?
(I wouldn't recommend it, passing the parameters values based on their position would be error-prone)