I'm trying to do something very simple, yet I can't seem to find the proper way to do it.
I have a MySqlDataAdapter object which contains the result of a query. I want to parse the results of this query before rendering them in an ASP.NET Repeater. (convert date from Unix Epoch to human readable, that sort of things).
So far, I'm unable to simply find how to create a loop that will allow me to move row by row in my SQL result, parse a couple of fields and change the content of some fields.
I'm also uncertain if I can do this directly from the MySqlDataAdapter, or from a DataSet, or from a DataTable. Most of the examples I have seen on the web don't cover that specific topic.
First you can fill a DataTable with the results:
DataTable table = new DataTable();
adapter.Fill(table);
After that you can loop through the DataTable and do your modfications:
foreach (DataRow row in table.Rows) {
row["MyDate"] = DoMagic(row["MyDate"]);
}
You can not loop your result set over DataAdapter object. You should fill your results into a DataTable, then it will be very simple to loop the rows :
DataSet myDataSet = new DataSet();
myDataAdapter.Fill(myDataSet);
if (myDataSet.Tables.Count > 0)
{
foreach (DataRow drResult in myDataSet[0].Rows)
{
// Do some stuff here over your row...
}
}
Do it inside a dataset.
populate the dataset from the dataadapter, then loop through the records in the dataset and modify those before binding it to the repeater.
Something like:
DataSet ds = new DataSet();
da.Fill(ds);
foreach(DataRow row in ds.Tables[0].Rows)
{
row[0] = ParseThisField(row[0]);
}
// then do your databind
Is a bit of a hacky way to do it though, but should work well enough for your purposes.
Related
I am running a pretty intensive data query (hence the long timeout) but wanted to know how to sort a DataTable correctly.
My code starts like so:
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand command = new SqlCommand(sql, conn);
command.CommandTimeout = 36000;
da.SelectCommand = command;
DataTable dt = new DataTable();
da.Fill(dt);
DataView dv = new DataView(dt);
// Sorting
dv.Sort = "theId DESC";
int i = 0;
while (dt.Rows.Count > 0 && i < 5)
{
DataRow row = dt.Rows[i];
string theId = row["theId"].ToString();
i++;
}
The theId has about 2,000 records with that are numerically sequential from 1 to 2,000.
The caveats or not using an ORDER BY in the SQL are due to the exception:
ERROR: Exception occurred
The query processor could not produce a query plan because a worktable is required, and its minimum row size exceeds the maximum allowable of 8060 bytes, etc.
I also cannot on-the-fly create a #TempTable due to max column size of 1,024.
The reasons the query is written a certain way are due to limitations of the system and network I am given, and cannot be adjusted nor can the query be run locally.
How do I get the sorted DataTable to work as that is what needs to be passed into the next function which is also outside of my control due to it being an api call to another system?
You can't really sort a DataTable. You do it via a DataView, as you have done, but that only sorts the view, not the table. If you then access the data via the Rows collection, you won't see the sort. You have to access the data via the DataView.
There's actually no need to create a DataView explicitly though. Every DataTable already has a DataView in its DefaultView property. When you bind a DataTable in WinForms, that's where the dusplayed data comes from. That's how you can sort the data in a DataGridView or via a BindingSource.
When you use the Rows collection, you get DataRow objects. When you use the DefaultView, you get DataRowView objects. They are quite similar in many ways but also have some differences. If you just want the data, you can index either using the column name and get the value, so they work the same way in that regard. If you access the data via the DefaultView but need the DataRow for some reason, you can access it via the Row property of the DataRowView. Try this code to see how it all works:
var table = new DataTable();
table.Columns.Add("Name", typeof(string));
table.Rows.Add("Peter");
table.Rows.Add("Paul");
table.Rows.Add("Mary");
Console.WriteLine("Rows, unsorted");
foreach (DataRow row in table.Rows)
{
Console.WriteLine(row["Name"]);
}
Console.WriteLine("DefaultView, unsorted");
foreach (DataRowView rowView in table.DefaultView)
{
Console.WriteLine(rowView["Name"]);
}
table.DefaultView.Sort = "Name";
Console.WriteLine("Rows, sorted");
foreach (DataRow row in table.Rows)
{
Console.WriteLine(row["Name"]);
}
Console.WriteLine("DefaultView, sorted");
foreach (DataRowView rowView in table.DefaultView)
{
Console.WriteLine(rowView["Name"]);
}
Console.WriteLine("DefaultView to DataRow, sorted");
foreach (DataRowView rowView in table.DefaultView)
{
Console.WriteLine(rowView.Row.Field<string>("Name"));
}
You'll be able to see from that that the data in the Rows collection is the same before and after the sort whereas the DefaultView shows data in the specified order. The last loop shows how you can access the DataRows from the DataRowViews and then use them where DataRowViews can't be, e.g. in LINQ to DataSet methods.
Note that, if you really do require the DataTable itself to be sorted then you can call ToTable on the DataView to generate a new DataTable. The new table will contain data based on the Sort and RowFilter properties of the DataView and you can also omit some columns if you want. You can also specify that only distinct records should be included.
I am assigning data to a Dataset manually from the data of another Dataset, in which two conditions are met one when there is data from another Dataset where the date field matches the rows with this data, otherwise I add them as a new row. This is perfect.
The problem is that when you finish assigning the data to the Dataset, the data that shows first are the ones that are updated with the first condition.
I need the data to be sorted by Date either dd\MM\yyyy or yyyy/MM/dd without taking into account the hours, and regardless of whether it was updated or added, but to order it by Date of ASC mode.
//foreach (DataRow dr in ds.Tables[0].Rows)
foreach (DataRow dr in ds.Tables[0].AsEnumerable().OrderBy(x=>x.Field<DateTime>("date").Date).ToList())
{
var row=dataset_manually.Tables[0].AsEnumerable().Where(x=> x.Field<DateTime>("date").Date == ((DateTime)dr["date"]).Date).FirstOrDefault();
if (row!=null)
{
//Update the data
row["entryToTurn"]=(DateTime)dr["entryToTurn"];
row["departureToTurn"]=(DateTime)dr["departureToTurn"];
row["turn"]=dr["turn"].ToString();
}
else
{
//Add new rows
var row2= dataset_manually.Tables[0].NewRow();
row2["entryToTurn"] = dr["entryToTurn"];
row2["departureToTurn"] = dr["departureToTurn"];
row2["turn"] = dr["turn"].ToString();
dataset_manually.Tables[0].Rows.Add(fila2);
}
}
For some reason the OrderBy in the foreach does not work. adds the data but does not order it. foreach (DataRow dr in ds.Tables[0].AsEnumerable().OrderBy(x=>x.Field<DateTime>("date").Date).ToList())
I tried this but it did not work:
dataset_manually.Tables[0].DefaultView.Sort = "date asc";
And I can not do it like this:
datagridview1.Sort(datagridview1.Columns[0], ListSortDirection.Ascending);
Because this only shows the data ordered in the DataGridView but when using the Dataset in another side the data is not sorted and the positions of the values in the grid are not the same things in the Dataset.
Desired output:
Note: The data is NOT assigned by the index, it must be assigned where the date field matches
Environment: Visual Studio 2010 (WindowsForms C#) & .NET NetFramework 4
Your code is not working because you first sort your data set and then you add new rows to it (so after everything)
Solution for this is slow if you have a lot of rows inside data set so I AM RECOMMENDING TO DO NOT DO THIS BUT SORT DATA AFTER LOADING IT INTO CODE.
Solution to this problem could be:
Load Data from DB into dataGridView
Get dataSource from dataGridView as DataTable
Add new data to DataTable
Sort DataTable
Save sorted data
Sorting could be done with:
DataView dv = data.DefaultView;
dv.Sort = "PrimaryColumn asc" //desc for descending
data = dv.ToTable();
I have a datatable filled with a report from a web service. I am now trying to display the datatable in an datagridview. This is the code I use to build the datatable:
// Create DataTabe to handle the output
DataTable dt = new DataTable();
dt.Clear();
dt.Columns.Add("EmployeeFirstName");
dt.Columns.Add("EmployeeLastName");
dt.Columns.Add("DepartmentName");
dt.Columns.Add("DepartmentCode");
dt.Columns.Add("LocationName");
dt.Columns.Add("DivisionCode");
dt.Columns.Add("EarningName");
dt.Columns.Add("OTHours");
dt.Columns.Add("WorkDate")
Fill the new datatable:
foreach (ReportRow row in report.Rows)
{
dt.Rows.Add(string.Join(",", row.ColumnValues));
}
Then I try to bind the data in the datatable to the dataGridview:
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = dt;
dataGridView1.Refresh();
When I run the application it only displays the data from the first column in the datatable. Do I need a loop of sorts to work through the columns or am I just missing a step?
Yes that's cause you are adding only one value to your dt when you say dt.Rows.Add(string.Join(",", row.ColumnValues));. You should be doing something like below (assuming that ReportRow also has the columns with same names like "EmployeeFirstName" else change the names accordingly)
foreach (ReportRow row in report.Rows)
{
DataRow dr = dt.NewRow();
dr["EmployeeFirstName"] = row["EmployeeFirstName"];
dr["EmployeeLastName"] = row["EmployeeLastName"];
dr["DepartmentName"] = row["DepartmentName"];
//rest of the columns fill
//once all columns filled
dt.Rows.Add(dr);
}
dt.Rows.Add(string.Join(",", row.ColumnValues)); -> You can either add a single DataRow item or a array of objects.
From your call, you chose the later, you are adding a array of objects, except you are adding ONE SINGLE object.
string.Join(",", row.ColumnValues) is one object.
Well after sleeping I have found the issue with dropping it into an sql table... I didn't take into account that the export to a CSV and the addition of the " , " would affect the export to sql. Here is the modification of the lines of code that was the issue:
foreach (ReportRow row in report.Rows)
{
dt.Rows.Add(row.ColumnValues);
}
Thank you all for your responses!
Is it possible to add a row to the middle of an existing dataset with c#? I've done a lot of searching and haven't been able to find anything on how to do this. What have I tried? I've tried searching a lot and haven't found anything like an 'insertAt' method for datasets.
Thanks
Mike
The DataSet consists of a collection of DataTable objects so I assume that you are talking about a Datatable, right? If so, it has an InsertAt method:
DataTable dt = dataset.Tables[0]; //Get first datatable from dataset
DataRow row = dt.NewRow();
//fill row
dt.Rows.InsertAt(row,3); //Insert at index 3
DataSet does not have a rows collection, so you can't add a row to it at all.
You can insert a row by index into a DataTable object using DataTable.Rows.InsertAt(row, i). If the table is in a DataSet, your syntax would be DataSet.Tables[i].Rows.InsertAt(row, 0)
In my opinion (though this could take a lot of time), you can create an array or a list array then transfer all the data there from your dataset through for loop or any loop...then put an if statement inside to check where you want to put your extra data like this:
List<string> arrayList = dataset;// i know this is not possible just showing you that you have to put all your data from dataset to array:)
List <string> newList = new List<string>();//its up to you if you want to put another temporary array or you could simply output your data from the loop.
//THE LOOP
for(int i = 0; i<=arrayList.Count(); i++){
if(i == x)//x is the index or you may change this statement its up to you
{
//do the print or pass the data to newList
newList.add(arraList[i]);//not sure about this. its been a while since the last time i use this array list..
}
}
another way is customize your query(if your pulling out some data from database)
happy coding:)
Here's a short sample of doing it:
class Program
{
static void Main(string[] args)
{
DataSet ds = new DataSet();
DataTable dt = ds.Tables.Add("Table");
dt.Columns.Add("Id");
for (int i = 0; i < 10; i++)
{
dt.Rows.Add(new object[]{i});
}
var newRow=dt.NewRow();
newRow.ItemArray=new string[]{(dt.Rows.Count/2).ToString()+".middle"};
dt.Rows.InsertAt(newRow, dt.Rows.Count / 2);
}
}
I have a DataTable available with me which contains thousands of rows. There is a column called EmpID which is containing '0' for some of the rows. I want to remove them from my current DataTable and want to create a new correct DataTable. I cannot go row by row checking it since it contains huge amount of data. Give me a suggestion to overcome this problem.
the best way would be to filter it at source (if possible) - so if you are creating it from a db, exclude all 0 values in your sql query itself using a where
starting .net 2.0, ms enhanced the filtering logic on the datatable to a great extent. so if you used the dataview (on top of your datatable) and added the where clause in there and added some sort of runtime indexes on this field, it would give you the desired results without looping over all records
You can use DataTable.Select("EmpID <> 0"). This will return an array of DataRows which you can create your new DataTable from if required.
Isn't it possible to first select the rows with EmpID = 0 and then iterate over these only ?
DataTable newTable = new DataTable();
foreach (DataRow dr in oldTable.Select("EmpID = '0'")) {
newTable.Rows.Add(dr);
oldTable.Rows.Remove(dr);
}
You can try
DataRow[] temp=
table.Select("EmpID ='0'");
foreach(DataRow dr in temp)
{
table.Rows.Remove(dr);
}
table.acceptchanges();