How do I add data from cache to a DataTable? - c#

I am embarrassed to ask, but what is the best way to add key/value pair data in cache (HttpRuntime.Cache) to a DataTable?
I'm currently dumping the key/value pair data from cache into a HashTable, which becomes the DataSource for a Repeater object. Unfortunately, I cannot sort the data in the HashTable and therefore thought a DataTable (being the DataSource for the Repeater) would solve my dilemma.

If you simply want to copy each key/value pair from the cache to a DataTable:
DataTable table = new DataTable();
table.Colums.Add("key", typeof(string));
table.Colums.Add("value", typeof(string));
foreach (DictionaryEntry entry in HttpRuntime.Cache)
{
table.Rows.Add(entry.Key, entry.Value);
}
This assumes that both keys and values are of type string, but if this is not the case, simply replace the types mentioned in line #2 and #3 in the code.
The newly created DataTable can be bound to a Repeater using code like this:
myRepeater.DataSource = table;
myRepeater.DataBind();

Have you had a look at SortedList Class, or SortedDictionary Class
Represents a collection of key/value
pairs that are sorted by key based on
the associated IComparer<(Of <(T>)>)
implementation.

Is there some reason you odn't want to store the Original Data table in your cache? (Besides the obvious high object weight of it, I mean?) Is it something you can share between all users in a read-only fashion? If so, it's probably a good candidate for caching in some format (maybe IDictionary?).

Or you can create you own class having the properties it will be bind to the repeater later on and add them into list of that type and you can sort them easily by linq
//your data container class
public class MyClass
{
public string Name { get; set; }
}
//Put all classes into the list before caching it
List<MyClass> source = new List<MyClass>() ;
//use this to sort with any kind of data inside your own defined class
var sortedResult = source.OrderBy(x => x.Name);

This should do the trick:
Sub Main() Handles Me.Load
Dim Hash As New Hashtable
Hash.Add("Tom", "Arnold")
Hash.Add("Sly", "Stallone")
HashToDataTable(Hash)
End Sub
Function HashToDataTable(ByVal Hash As Hashtable) As Data.DataTable
Dim Table As New Data.DataTable()
Table.Columns.Add("Key", GetType(String))
Table.Columns.Add("Value", GetType(Object)) 'You can use any type you want.
For Each Key In Hash.Keys
Table.Rows.Add(Key, Hash(Key))
Next
Return Table
End Function

Related

Is it better to create a List of new Objects or Dictionary?

I have a file with 2 columns and multiple rows. 1st column is ID, 2nd column is Name. I would like to display a Dropdown where I will show only all the names from this file.
I will only iterate through the collection. So what is the better approach? Is creating the objects more readable for other developers? Or maybe creating new objects is too slow and it's not worth.
while (!reader.EndOfStream)
{
var row = reader.ReadLine();
var values = row.Split(' ');
list.Add(new Object { Id = int.Parse(values[0]), Name = values[1] });
}
or
while (!reader.EndOfStream)
{
var row = reader.ReadLine();
var values = row.Split(' ');
dict.Add(int.Parse(values[0]), values[1]);
}
Do I lose the speed in the case if I will create new objects?
You create new objects, so to speak, also while adding to the Dictionary<T>, you create new Key-Value pair of the desired type.
As you already mentioned in your question, the decision is made on primary
expected access pattern
performance considerations, which are the function also of access pattern per se.
If you need read-only array to iterate over, use List<T> (even better if the size of the data is known upfront use Type[] data, and just read it where you need it).
If you need key-wise access to your data, use Dictionary<T>.
If you want to only iterate objects, then use List. No need to use Dictionary class at all.

How to add a new property into each list item in a C# list

I'm a C# novice. I was searching for this without any luck.
Assume I have a database result converted to a list. Something like the following
var schedules = db.Schedules.Where(s => s.RequestId == id).ToList();
Now i need to add a new element to this list. Not a list item but a property for each list item existing in the list.
For example in php if its a multidimensional array i can use a foreach to loop through the array and it is simple as $arrayList['new_key'] = "new_value";
How can I add a property like that to the above schedules list in C#? To be more precise; Schedule is a dataset. And the new property is also something i want to fetch from a another property of a different dataset.
Help much appreciated.
Edit:
Now i realized what i really need. I need to make a left outer join to connect both Schedule and the other model. I have oped a new question:
How to create a simple left outer join in lambda expression in EF ASP.NET MVC5
"Schedule" (or whatever object set is returned) needs to have the property added1. So either add the property to the object, or create a new object with the original object's properties (plus one more) and select into that. e.g.
class Schedule2 : Schedule
{
public String NewProperty { get; set; }
public Schedule2(Schedule schedule)
{
// assign original properties here from "Schedule". e.g.
base.RequestId = schedule.RequestId;
}
}
Then:
var schedules = db.Schedules
.Where(x => x.RequestId == id)
.Select(x => new Schedule2(x))
.ToList();
1 Notwithstanding the DynamicObject, but I don't think it's appropriate in this case.
You said that Schedule was a dataset. I assume from this that Schedule is an instance of System.Data.DataSet with a single table, or of System.Data.DataTable directly.
It's very easy to add an extra property to a DataTable. All you have to do ahead of time is create and add a new DataColumn to the Columns property of the DataTable. Something like this:
DataSet ds1 = <whatever method returns the dataset>
DataTable dt1 = ds1.Tables[0];
dt1.Columns.Add("NewCol", typeof(string));
You will now be able to use "NewCol" as an indexer on any DataRow from dt1:
dt1.Rows[0]["NewCol"] = "a simple string";

How to typecast to datarow from string

'cannot implicitly convert type string to data row[]'.
Is it possible to store the string type to data row[]? I need to store the value of the particular column in that particular data row array. Suggest me an answer please.
DataRow[] drprocess = objds.Tables[0].Rows[i]["ProcessName"].ToString();
You have declared a variable of type DataRow[] called drProcess but have not yet created an array of DataRows in which to put any values. Instead you've tried to tell the compiler that the string you're retrieving is actually a DataRow, which it isn't.
It's possible that what you want to do is to create your array of DataRows, then create a DataRow object and assign it into the array. However, I'm suspicious that this isn't actually what you're trying to achieve. Note that objds.Tables[0].Rows is already a collection of DataRows. You can actually edit or use this collection yourself if you need.
Or if you're wanting to create a new collection of process names you might be better creating a var processes = new List<string>() then calling process.Add(objds.Tables[0].Rows[i]["ProcessName"].ToString()).
It all depends what you want to do with this collection of process names afterwards.
First, a DataRow always belongs to a DataTable. To which table should these new DataRow belong? I will presume objds.Tables[0].
I also assume that you have a string-column and you want to split every field in it to a DataRow[], then we need to know the delimiter.
Presuming it is a comma:
DataRow[] drprocess = objds.Tables[0].Rows[i].Field<string>("ProcessName").Split(',')
.Select(name => {
DataRow row = objds.Tables[0].NewRow();
row.SetField("ProcessName", name);
return row;
})
.ToArray();

Order DataTable rows with Dictionary

I'm trying to pass an ArrayList into a DataRow object, the idea being to import data into a database from a CSV.
Previously in the file, a Dictionary<string,int> has been created, with the column name as the Key, and the position index as the corresponding value.
I was planning on using this to create a temporary DataTable for each record to aid importing into the DB. My original idea was something along the lines of:
private DataRow ArrayListToDataRow(ArrayList data, Dictionary<string,int> columnPositions)
{
DataTable dt = new DataTable();
DataColumn dc = new DataColumn();
for (i=0;i<=data.Count;i++)
{
dc.ColumnName = columnPositions.Keys[i];
dt.Columns.Add(dc);
dt.Columns[columnPositions.Keys[i]].SetOrdinal(columnPositions(columnPositions.Keys[i]);
}
//TODO Add data to row
}
But of course, the keys aren't indexable.
Does anybody have an idea on how this could be achieved?
Since the size of data should be the same as the size of your columnPositions, you could try using a foreach over your dictionary instead of a for loop.
If you want to access your dictionary values based on a sortable index, you would need to change it to
Dictionary<int, string>
Which seems to make more sense, as you seem to want to read them in that order.
If you cannot change the dictionary, you can do something like this
var orderedPositions = columnPositions.OrderBy(x => x.Value);
foreach(var position in orderedPositions)
{
// do your stuff using position.Key and position.Value
}
.OrderBy comes from Linq, so yuo will need to add
using System.Linq;
to your class.
By ordering the columnPositions on their value (the columnIndex) instead of the default (the order in which items were added), you can loop trough them in the order you presumably want (seeing as you were going with a for loop and every time trying to get the next columnPosition).

how to add an associative index to an array. c#

i have an array of custom objects. i'd like to be able to reference this array by a particular data member, for instance myArrary["Item1"]
"Item1" is actually the value stored in the Name property of this custom type and I can write a predicate to mark the appropriate array item. However I am unclear as to how to let the array know i'd like to use this predicate to find the array item.
I'd like to just use a dictionary or hashtable or NameValuePair for this array, and get around this whole problem but it's generated and it must remain as CustomObj[]. i'm also trying to avoid loading a dictionary from this array as it's going to happen many times and there could be many objects in it.
For clarification
myArray[5] = new CustomObj() // easy!
myArray["ItemName"] = new CustomObj(); // how to do this?
Can the above be done? I'm really just looking for something similar to how DataRow.Columns["MyColumnName"] works
Thanks for the advice.
What you really want is an OrderedDictionary. The version that .NET provides in System.Collections.Specialized is not generic - however there is a generic version on CodeProject that you could use. Internally, this is really just a hashtable married to a list ... but it is exposed in a uniform manner.
If you really want to avoid using a dictionary - you're going to have to live with O(n) lookup performance for an item by key. In that case, stick with an array or list and just use the LINQ Where() method to lookup a value. You can use either First() or Single() depending on whether duplicate entries are expected.
var myArrayOfCustom = ...
var item = myArrayOfCustom.Where( x => x.Name = "yourSearchValue" ).First();
It's easy enough to wrap this functionality into a class so that external consumers are not burdened by this knowledge, and can use simple indexers to access the data. You could then add features like memoization if you expect the same values are going to be accessed frequently. In this way you could amortize the cost of building the underlying lookup dictionary over multiple accesses.
If you do not want to use "Dictionary", then you should create class "myArrary" with data mass storage functionality and add indexers of type "int" for index access and of type "string" for associative access.
public CustomObj this [string index]
{
get
{
return data[searchIdxByName(index)];
}
set
{
data[searchIdxByName(index)] = value;
}
}
First link in google for indexers is: http://www.csharphelp.com/2006/04/c-indexers/
you could use a dictionary for this, although it might not be the best solution in the world this is the first i came up with.
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("cat", 2);
d.Add("dog", 1);
d.Add("llama", 0);
d.Add("iguana", -1);
the ints could be objects, what you like :)
http://dotnetperls.com/dictionary-keys
Perhaps OrderedDictionary is what you're looking for.
you can use HashTable ;
System.Collections.Hashtable o_Hash_Table = new Hashtable();
o_Hash_Table.Add("Key", "Value");
There is a class in the System.Collections namespace called Dictionary<K,V> that you should use.
var d = new Dictionary<string, MyObj>();
MyObj o = d["a string variable"];
Another way would be to code two methods/a property:
public MyObj this[string index]
{
get
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
return o;
}
}
}
set
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
var i = My_Enumerable.IndexOf(0);
My_Enumerable.Remove(0);
My_Enumerable.Add(value);
}
}
}
}
I hope it helps!
It depends on the collection, some collections allow accessing by name and some don't. Accessing with strings is only meaningful when the collection has data stored, the column collection identifies columns by their name, thus allowing you to select a column by its name. In a normal array this would not work because items are only identified by their index number.
My best recommendation, if you can't change it to use a dictionary, is to either use a Linq expression:
var item1 = myArray.Where(x => x.Name == "Item1").FirstOrDefault();
or, make an extension method that uses a linq expression:
public static class CustomObjExtensions
{
public static CustomObj Get(this CustomObj[] Array, string Name)
{
Array.Where(x => x.Name == Name).FirstOrDefault();
}
}
then in your app:
var item2 = myArray.Get("Item2");
Note however that performance wouldn't be as good as using a dictionary, since behind the scenes .NET will just loop through the list until it finds a match, so if your list isn't going to change frequently, then you could just make a Dictionary instead.
I have two ideas:
1) I'm not sure you're aware but you can copy dictionary objects to an array like so:
Dictionary dict = new Dictionary();
dict.Add("tesT",40);
int[] myints = new int[dict.Count];
dict.Values.CopyTo(myints, 0);
This might allow you to use a Dictionary for everything while still keeping the output as an array.
2) You could also actually create a DataTable programmatically if that's the exact functionality you want:
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("ID", typeof(int));
DataColumn dc2 = new DataColumn("Name", typeof(string));
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
DataRow row = dt.NewRow();
row["ID"] = 100;
row["Name"] = "Test";
dt.Rows.Add(row);
You could also create this outside of the method so you don't have to make the table over again every time.

Categories

Resources