Store Columns in List sql c# - c#

while (Running)
{
while (rdr.Read())
{
List<PackageDetailFile> pkgFiles = rdr.Read().ToString().ToList();
}
}
Hello, the read() returns an inner joined table which has 7 8 columns, is it possible to store them inside List ?
if we can hows the correct casting of rdr.read(), ( to string to list ... ? )

Depending on the structure of your PackageDetailFile class and the underlying data you could do something like this
var packageDetailFiles = new List<PackageDetailFile>();
while (Running)
{
while (rdr.Read())
{
var detailFile = new PackageDetailFile();
// the following will depend on your data structure and class properties
detailFile.Property1 = rdr.GetString(0);
detailFile.Property2 = rdr.GetString(1);
detailFile.Property3 = rdr.GetString(2);
packageDetailFiles.Add(detailFile);
}
}
Note: You can use assemblies like AutoMapper to map from a data reader to a POCO reducing the need for the tedious MyObject.MyProperty = dataReader[collectionIndex] making your code far more readable and test friendly.

try use GetValues method of rdr object. I suppose rdr is a SqlDataReader or another DataReader.
This method return an object array with all columns of the current row.
After it you can store the object array in a list of objects. If you want to store in another type of list you must cast every element to the correct type before storing it.

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.

c# Variable Declaration

I'm building a console application on visual studio that involves some SQL. Basically, I have a database table with a large amount of columns, and I need set them as variables and have a way of addressing them efficiently. Right now I'm thinking an array which I can then loop through. Here's sort of what my code looks like right now:
SqlCommand getColumns = new SqlCommand("SELECT * FROM tableName",
connection1);
myReader = getColumns.ExecuteReader();
while (myReader.Read())
{
string[] array = new string { myReader["ColumnName"].ToString(),
myReader["ColumnName2"].ToString, etc...};
for (int i = 0; i <= array.length; i++) {
some action...array[i];
}
}
I admit I'm somewhat new to c# and this kind of development, so let me know if there's a more efficient way to do this or if I need to post more code. Thanks!
You do not need custom type for this. .NET already gives you DataSet and DataTable. You need DataTable since it's just one result set, and results look just as same as you see in SSMS results window.
var dt = new DataTable();
dt.Load(myReader);
If you have a lot of columns, accessing them by index instead of name would be more efficient:
string[] array = new string[myReader.FieldCount];
for(int i=0; i<myReader.FieldCount; i++)
{
array[i] = myReader[i].ToString();
}
Also, if you know the number of columns in advance (which is usually the case), you could move array declaration out of while(myReader.Read()), resulting in less memory allocation due to reusing same array.
Another suggestion is that you might not want to convert everything to string... Declare array of objects and handle each data type as you wish. Integer probably should be assined to some entity's integer property instead of saving in string array.
Personally I would declare some entity and declare a List of those. Then populate the list from database:
public class MyEntity
{
public string Name { get; set; }
public int Age { get; set; }
//Other properties
}
//...
SqlCommand getColumns = new SqlCommand("SELECT * FROM tableName",
connection1);
var myDataFromTable = new List<MyEntity>();
myReader = getColumns.ExecuteReader();
while (myReader.Read())
{
myDataFromTable.Add(new MyEntity {
Name = myReader[0] as string,
Age = (int)myReader[1]
//...
});
}
//Process your list of entities here
Another approach may be not to save everything into memory (as you do now), but process data on the fly - everything depends on your requirements and the size of data set. But anyway I recommend parsing data to some entity and work with that.
As per my understanding - On way of doing it.
We can create a class containing properties similar to that of columns in table. In the while loop you can create object of that class, then set the properties with the respected columns and add that object to Arraylist (Arraylist containing the class objects ).
Reference Link : https://msdn.microsoft.com/en-us/library/system.collections.arraylist(v=vs.110).aspx
Hope its helps.

Populate a List<T> and DataGridView with contents of an SqlDataReader

I am trying to write a function that can take three parameters: an SqlDataReader, a DataGridView and a List.
I want to take the contents of the SqlDataReader and create a list of Objects, then bind this to the DataGridView.
With a few pointers from another Stack Overflow user I came up with the following:
public void FillArrayList<T>(DataGridView grid, SqlDataReader reader, List<T> list)
{
//Fill the list with the contents of the reader
while (reader.Read())
{
Object obj = new Object();
Type type = typeof(T);
FieldInfo[] fields = type.GetFields(); // Get the fields of the assembly
int i = 0;
foreach(var field in fields)
{
field.SetValue(obj, reader[i]); // set the fields of T to the reader's value
i++;
}
list.Add((T)obj);
}
grid.DataSource = list;
}
When I run the code, I get an error when casting the object to type T:
Unable to cast object of type 'System.Object' to type
'TestHarness.Organisation'.
I was under the impression that an Object could store anything. Can anyone advise me on why this cast cannot be performed?
Thanks,
Andy
You can cast nearly anything to Object, but you can't cast Object to anything. Take a look at the System.Object class on MSDN. Notice how there's almost nothing there. The cast doesn't make sense because it's functionally the same as doing calling a new TestHarness.Organization.
If you know exactly what you're looking for in the DataReader to go into TestHarness.Organization or whatever it is, you might try a user-defined conversion. This would allow you to either implicitly or explicitly call some code to do the type change for you without any extra code on the spot.
With a little help from the link posted by MMK, in the comment below my question, I have devised a solution:
public void FillList<T>(DataGridView grid, string SQLCommand, List<T> list) where T : class, new()
{
//Load the data into the SqlDataReader
SqlCommand dataCommand = new SqlCommand();
dataCommand.Connection = dataConnection;
dataCommand.CommandType = CommandType.Text;
dataCommand.CommandText = SQLCommand;
SqlDataReader dataReader = dataCommand.ExecuteReader();
//Fill the list with the contents of the reader
while (dataReader.Read())
{
var obj = new T();
//Get the property information
PropertyInfo[] properties = typeof(T).GetProperties();
int i = 0;
foreach(var property in properties)
{
property.SetValue((T)obj, dataReader[i], null); // set the fields of T to the reader's value
i++;
}
list.Add(obj);
}
dataReader.Close();
//Bind the list to the DataGridView
grid.DataSource = list;
}
Seems to do exactly what I need. It's possible I may come across some obvious error as I use this in more and more situations, but, this is life.
Thanks for your help, guys!

Problem in converting a generic list<string> or string[] array to datatable

I have the below function
public static DataTable ToTable<T>(this IEnumerable<T> listItem)
{
//Return null if the list is empty
if (listItem == null || listItem.Count() == 0) return null;
//Gets the type of the object
var listType = listItem.First().GetType();
//Initialize a new datatable
var dataTable = new DataTable(listType.Name);
//Create the datatable column names and types
listType.GetProperties().ToList().ForEach(col => dataTable.Columns.Add(col.Name, col.PropertyType));
//Get the datatable column names
var dataTableColumnNames = dataTable.GetDatatableColumnNames();
listItem.ToList().ForEach(item =>
{
//create a new datarow
var dataRow = dataTable.NewRow();
dataTableColumnNames
.Where(propName => listType.GetProperty(propName) != null)
.ToList()
.ForEach(columnName =>
//Exception happens here in the next line
dataRow[columnName] = listType.GetProperty(columnName).GetValue(item, null));
//Add the row to the data table
dataTable.Rows.Add(dataRow);
});
//Commit the changes to the datatable
dataTable.AcceptChanges();
return dataTable;
}
It works great for dictionary object and generic list as List<MyClass> .. but not for
List<string> or string[].
For those I am getting an exception as Parameter count mismatch.
The error is coming at
dataRow[columnName] = listType.GetProperty(columnName).GetValue(item, null));
What is the mistake that is happening?
Please help
Here's the deal. The index operator is actually considered a property when using reflection, hence parameter count mismatch.
If you break into your code and check the properties that are actually being enumerated by GetProperties(), you'll see the "Chars" property. That's the String's index operator. Since you didn't provide an index, you're getting a Parameter Count Mismatch error.
In essence, I assume string doesn't have any properties you want to put in your data table, but rather the string instance IS what you want to put in the data table.
You could create a model to store the string in, with the string as a property on the model, then the string would be stored with your current code. Otherwise, you will need to rethink your table generation algorithm for primitive types.
I hope this helps :)
Because one of the public properties of string is an indexer and you pass null as the index value. So you effectively end up doing this: string[null] which ends up in an exception.
I haven't verified this as I don't have VS available right now so I might be wrong but I'm pretty sure that's the problem.
Update: This question answers how you detect an indexed property: C# Reflection Indexed Properties

Fill an array (or arraylist) from SqlDataReader

Is there a way to fill an array via a SqlDataReader (or any other C# ADO.NET object) without looping through all the items? I have a query that is returning a single column, and I want to put that into a string array (or ArrayList, or List, etc).
It is possible. In .NET 2.0+, SqlDataReader inherits from DbDataReader, which implements IEnumerable (non-generic one). This means that you can use LINQ:
List<string> list = (from IDataRecord r in dataReader
select (string)r["FieldName"]
).ToList();
That said, the loop is still there, it's just hidden in Enumerable.Select, rather than being explicit in your code.
No, since SqlDataReader is a forward-only read-only stream of rows from a SQL Server database, the stream of rows will be looped through whether explicitly in your code or hidden in a framework implementation (such as DataTable's Load method).
It sounds like using a generic list and then returning the list as an array would be a good option. For example,
List<int> list = new List<int>();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(reader.GetInt32(0));
}
}
return list.ToArray();
In response to your comment, calling ToArray() may be overhead, it depends. Do you need an array of objects to work with or would a generic collection (such as List<T> or ReadOnlyCollection<T>) be more useful?
Apparently, ever since .NET 1.1 SqlDataReader had the following method:
int size;
object[] data = new object[]{};
size = reader.GetValues(data);
This populates data with the values of the current reader row, assigning into size the number of objects that were put into the array.
Since any IDataReader implementation (SqlDataReader included) will be a forward-only reader by definition, no there is no way to do this without looping. Even if there were a framework library method to do this it would have to loop through the reader, just like you would.
The orignial OP asked for Array, ArrayList or List. You can return Array as well. Just call the .ToArray() method and assign it to a previously declared array. Arrays are very fast when it comes to enumerating each element. Much faster than a List if the list has more than 1000 elements.
You can return to Array, List, or Dictionary.
ids_array = (from IDataRecord r in idReader
select (string)r["ID"]).ToArray<string>();
Additionally, if you are using a lookup of keys for example, you might consider creating a HashSet object with has excellent lookup performance if you are simply checking one list against another to determine if an elements key exists in the HashSet object.
example:
HashSet<string> hs = new HashSet<string>(
(from IDataRecord r in idReader select (string)r["ID"]).AsEnumerable<string>() );
You have to loop, but there are projects that can make it simpler. Also, try not to use ArrayList, use List instead.
You can checkout FluentAdo for one: http://fluentado.codeplex.com
public IList<UserAccount> List()
{
var list = new FluentCommand<UserAccount>("SELECT ID, UserName, Password FROM UserAccount")
.SetMap(reader => new UserAccount
{
ID = reader.GetInt("ID"),
Password = reader.GetString("Password"),
UserName = reader.GetString("UserName"),
})
.AsList();
return list;
}
If you read your SqlDataAdapter into a DataTable:
DataTable dt as DataTable;
dt.fill(data);
Then you can use some of the toys in System.Data.DataSetExtensions as referenced in Joel Muller's answer to this question.
In uses a bit of Linq, so you will net .Net 3.5 or higher.
var array = reader.GetValue("field_name") as long[];

Categories

Resources