I am working on Windows Form Application i have a DataTable Which contains 1000 rows and for paging my DataGridView i am fetching first 100 records from DataTable like this
DataTable rec = dt.Rows.Cast<DataRow>().OrderBy(x => x["RegNo"]).Take(100).CopyToDataTable();
I have also tried this
DataTable recc = dt.Rows.Cast<DataRow>().OrderBy(x => x["RegNo"]).Take(100).Skip(100).CopyToDataTable();
Question:
how to fetch next 100 records from DataTable when user click on next page and so on
You can skip and take.
DataTable rec = dt.Rows.Cast<DataRow>().OrderBy(x => x["RegNo"]).Skip(100).Take(100).CopyToDataTable();
You can have a variable that tracks current page.
var currPage = 1;
var page_size = 100;
var skip = currPage * page_size; //if 100 is page size......
DataTable rec = dt.Rows.Cast<DataRow>().OrderBy(x => x["RegNo"]).Skip(skip).Take(page_size).CopyToDataTable();
You can use Skip() and Take() functions. Better option would be to send page index and rows count per page as parameter to your function:
DataTable rec = dt.Rows.Cast<DataRow>()
.OrderBy(x => x["RegNo"])
.Skip(rowsCount * pageIndex)
.Take(rowsCount)
.CopyToDataTable();
Related
I was trying to connect a DataGridView to a SQL Server, and the solution outlined in https://stackoverflow.com/a/18113368/492336 uses a SqlDataAdapter and a DataTable:
var adapter = new SqlDataAdapter("select * from foo", "server=myhost-pc\\sqlexpress;trusted_connection=yes;database=test1");
var table = new DataTable();
adapter.Fill(table);
view.DataSource = table;
I'm trying to figure out if this method fetches the entire dataset from the server, or if it connects the DataGridView to the server so it can fetch new rows on demand.
For example if the table has 1 million rows, will all of them be fetched and written into the DataTable object before SqlDataAdapter::Fill has returned?
Limiting the number of rows loaded via SQL limits them either qualitatively (WHERE...) or via a rather blunt LIMIT clause. You can also use the DataAdapter to load rows in "pages" or groups - a bit at a time. This uses MySQL but it works with many of the other (all?) of the DBProviders:
int pageSize = 10000;
int page = 0;
...
The initial loading:
string SQL = "SELECT * FROM Sample";
using (MySqlConnection dbCon = new MySqlConnection(MySQLConnStr))
{
dtSample = new DataTable();
daSample = new MySqlDataAdapter(SQL, dbCon);
daSample.FillSchema(dtSample, SchemaType.Source);
dbCon.Open();
int Rows = daSample.Fill((page*pageSize), pageSize, dtSample);
}
dgv2.DataSource = dtSample;
this.lblPages.Text = String.Format("Rows {0} - {1}",
((page * pageSize) + 1),
(page + 1 * pageSize));
page += 1;
The key is the DataAdapter(int, int, DataTable) overload: it allows you to specify the first row and the number of rows to load. Rather than recreating the DataAdapter for each page I'd use a form/class level one. Reading the next pages leaves you some options:
dgv2.SuspendLayout();
dtSample.Rows.Clear();
int Rows = daSample.Fill((page * pageSize), pageSize, dtSample);
dgv2.ResumeLayout();
this.lblPages.Text = String.Format("Rows {0} - {1}",
((page * pageSize) + 1),
(page + 1 * pageSize));
if (Rows != pageSize) // last page?
page = 0;
else
page += 1;
If you do not clear the rows, the DataTable will accumulate them: that is, after loading the second set, it will have all the rows for pages 1 and 2.
It can be useful to allow them to accumulate so that any given set is loaded once only. If it is important to still limit the display to one page at a time, you can use a DataView to display only the current group:
yes , it will create object and will implement on your grid view to show your all data, the thing is that how you write the SQL query , you can limit the data rows by using some SQL keywords like TOP, LIMIT, OFFSET.
Is it possible to change order of rows in DataTable so for example the one with current index of 5 moves to place with index of 3, etc.?
I have this legacy, messy code where dropdown menu get it's values from DataTable, which get it's values from database. It is impossible to make changes in database, since it has too many columns and entries. My original though was to add new column in db and order by it's values, but this is going to be hard.
So since this is only matter of presentation to user I was thinking to just switch order of rows in that DataTable. Does someone knows the best way to do this in C#?
This is my current code:
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
foreach (DataRow row in result.Rows)
{
m_cboReasonCode.Properties.Items.Add(row["FLOKKUR"].ToString().Trim() + " - " + row["SKYRING"]);
}
For example I want to push row 2011 - Credit previously issued to the top of the DataTable.
SOLUTION:
For those who might have problems with ordering rows in DataTable and working with obsolete technology that doesn't supports Linq this might help:
DataRow firstSelectedRow = result.Rows[6];
DataRow firstNewRow = result.NewRow();
firstNewRow.ItemArray = firstSelectedRow.ItemArray; // copy data
result.Rows.Remove(firstSelectedRow);
result.Rows.InsertAt(firstNewRow, 0);
You have to clone row, remove it and insert it again with a new index. This code moves row with index 6 to first place in the DataTable.
If you really want randomness you could use Guid.NewGuid in LINQ's OrderBy:
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
var randomOrder = result.AsEnumerable().OrderBy(r => Guid.NewGuid());
foreach (DataRow row in randomOrder)
{
// ...
}
If you actually don't want randomness but you want specific values at the top, you can use:
var orderFlokkur2011 = result.AsEnumerable()
.OrderBy(r => r.Field<int>("FLOKKUR") == 2011 ? 0 : 1);
You can use linq to order rows:
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
foreach (DataRow row in result.Rows.OrderBy(x => x.ColumnName))
{
m_cboReasonCode.Properties.Items.Add(row["FLOKKUR"].ToString().Trim() + " - " + row["SKYRING"]);
}
To order by multiple columns:
result.Rows.OrderBy(x => x.ColumnName).ThenBy(x => x.OtherColumnName).ThenBy(x.YetAnotherOne)
To order by a specific value:
result.Rows.OrderBy(x => (x.ColumnName == 2001 or x.ColumnName == 2002) ? 0 : 1).ThenBy(x => x.ColumName)
You can use the above code to "pin" certain rows to the top, if you want more granular than that you can use a switch for example to sort specific values into sorted values of 1, 2, 3, 4 and use a higher number for the rest.
You can not change the order or delete a row in a foreach loop, you should create a new datatable and randomly add the rows to new datatable, you should also track the inserted rows not to duplicate
Use a DataView
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
DateView view = new DateView(result);
view.Sort = "FLOKKUR";
view.Filter = "... you can even apply an in memory filter here ..."
foreach (DataRowView row in view.Rows)
{
....
Every data table comes with a view DefaultView which you can use, this way you can apply the default sorting / filtering in your datalayer.
public DataTable GetMCCHABAKflokka(string tableName, string sort, string filter)
{
var result = GetMCCHABAKflokka(tableName);
result.DefaultView.Sort = sort;
result.DefaultView.Filter = filter;
return result;
}
// use like this
foreach (DataRowView row in result.DefaultView)
I have 100 records in my Datable says to be in
DataTable dt=new DataTable();
dt have 100 of records say column name as sub_id(contain int datatype) and subheadername(contain nvarchar(150)) , I want top 20 records from this dt in ascending order
I am putting code as
//dtlcategories.DataSource = dt.AsEnumerable().OrderBy(x => x["subheadername"]).Take(20).ToList();
dtlcategories.DataSource = dt.Rows.Cast<DataRow>().OrderBy(x => x["subheadername"]).Take(20).ToList();
dtlcategories.DataBind();
Here dtlcategories is Datalist but on running error is coming as 'System.Data.DataRow' does not contain a property with the name 'subheadername'.
ANSWER IS SOLVED
dtlcategories.DataSource = dt.Rows.Cast<DataRow>().OrderBy(x => x["subheadername"]).Take(20).copytodatatable();
dtlcategories.DataBind();
There's a couple different ways you can do this using LINQ. These will both return the same results.
dt.AsEnumerable().OrderBy(x => x["subheadername"]).Take(20);
dt.Rows.Cast<DataRow>().OrderBy(x => x["subheadername"]).Take(20);
If you're going to use the result as the source of data for another control, you may need to call .ToList() after .Take(x).
Edit:
I changed the column name based on your edit. If you want to sort by id instead (you didn't specify), just replace "subheadername" with "sub_id".
This query fetches top 20 records from db and then orders them by the sub_id column.
var topTwenty = dt.AsEnumerable().Take(20).OrderBy(r => r.Field<int>("sub_id"));
dt.AsEnumerable().OrderBy(row => row["sub_id"]).Take(20);
This will return you IEnumerable. Now iterate through the IEnumerable and add them to another data table. Now your final data table is ready!!
this code orders data according to date and takes first 100 row.
var table = new DataTable();
var t = table.AsEnumerable();
var result = t.OrderByDescending(f => f.Field<DateTime>(new DataColumn("Date"))).Take(100);
Update:
var table = new DataTable();
var t = table.AsEnumerable();
var result = t.OrderBy(f => f.Field<String>(new DataColumn("subheadername"))).Take(20)
A possible solution:
DataRow[] rows = dt.Select("sub_id< 100 ");
I have a DataSet with many DataTables each containing many columns plus a column buildingID.
I would like to filter the entire DataSet by giving it a value for buildingID. I would like the rows in every table with a buildingID of, say 343.
Is there any quick possible way in C#?
You can use DataTable.Select, which returns filtered rows from a DataTable matching a criteria.
foreach (DataTable table in dataset.Tables) {
var rows = table.Select("buildingID = " + buildingId.ToString());
// Do stuff with filtered rows
}
To easily get all the rows that match your criteria, here's a LINQ expression:
var rows = dataset.Tables.SelectMany(
t => t.Select("buildingID = " + buildingId.ToString()));
What about this?
var ds1 = new DataSet();
foreach (DataTable dt in ds1.Tables)
{
var filtereddt = dt.AsEnumerable().Where(row => row.Field<int>("buildingID") == 1).ToList();
//you can add these lists to another list array or something like that.
}
suppose i am having a database table with 20 records and of that i want to display only 10 records in the dataviewgrid control, how can i achieve this?
You can write a query like this:
SELECT * FROM (
SELECT TOP 10 * FROM (
SELECT TOP 20 * FROM MyTable ORDER BY MyID ASC
) AS NewTbl ORDER BY MyID DESC
) AS NewTbl2 ORDER BY MyID ASC
This selects records 11-20. If you want to select records 6-15 just change 20 to 15.
20 is the "last record to select" and 10 is the number of records before and up to 20.
Edit (After your comment about having all rows in a DataSet):
var newDS = new DataSet();
newDS.Tables.Add(oldDSWithAllRows.Tables["YourTableName"].Clone());
foreach (DataRow myDataRow in oldDSWithAllRows.Tables["YourTableName"].Rows)
{
if (/* Your criteria */)
{
newDS.Tables["YourTableName"].ImportRow(myDataRow);
}
}
myDataGridView.DataSource = newDS;
Select only the 10 records you want.
In SQL use the TOP clause:
SELECT TOP 10 * FROM myTable
use DataTable.Select
usage:
dataSet1.Tables[0].Select("Id>5");
or, better, DataView with a RowFilter, example here
you can set tha DataGridView.DataSource to this DataView
If you're using the latest version of C# you could filter your source with LINQ:
// change Skip to 10 to page through
var filtered = mydatasource.Skip(0).Take(10);
This assumes you've returned your SQL data as an IEnumerable<T>
Suppose we have the following table
DataTable dt = new DataTable();
int counter = 1;
dt.Columns.Add("ID");
dt.Columns.Add("Name");
for (int i = 1; i <= 20; i++)
{
DataRow dr = dt.NewRow();
dr["ID"] = i;
dr["Name"] = string.Format("Name{0}", i);
dt.Rows.Add(dr);
}
You can bind the grid this way:
this.GridView1.DataSource = dt.AsEnumerable().Take(10);
this.GridView1.DataBind();
but:
this can work if you did the following:
-Add two template fields to the gridview
-Add the following function to the code behind page:
protected object GetColumnValue(object Row,string columnName)
{
DataRow dr = Row as DataRow;
return dr[columnName];
}
Edit the DataBindings of the fields of the gridview to bind this way:
GetColumnValue(Container.DataItem,"ID") //for the first Field
GetColumnValue(Container.DataItem,"Name") //for the second field