string s = "primaryKeyValue";
DataRow foundRow = dataSet1.Tables["AnyTable"].Rows.Find(s);
if (foundRow != null)
{
foreach(DataRow r in dataTable)
{
if(r == foundRow)
r.Delete();
}
}
dataTable.AcceptChanges();
dataTable and dataSet1.Tables["AnyTable"] are different table.
dataTable is a clone of dataSet1.Tables["AnyTable"]
this code not working..If anyone know how to "find and delete row in datatable" let me know. Thanks in advance
You can use indexOf instead of returning all records to delete the data. You already know which row to delete.
I think that you have deleted one record directly from Pk, this code is more performant.
You must be set PK on Table
ds.Tables["AnyTable"].PrimaryKey = new[] { dt.Columns["YourPKcolumn"] };
DataRow dr = ds.Tables["AnyTable"].Rows.Find(PrimaryKeyValue);
int idx = dt.Rows.IndexOf(dr);
dt.Rows.RemoveAt(idx);
ds.Tables["AnyTable"].AcceptChanges();
Please try this.
var datatable = new DataTable(); // take your datatable
string s = "primaryKeyValue";
DataRow[] row = datatable.Select("name='" + s + "'");
for (int i = row.Length - 1; i >= 0; i--)
{
datatable.Rows.Remove(row[i]);
}
datatable.AcceptChanges();
Related
I have a DataTable called dt which is filled with values from excel.
On line 6 (row) i have my header information
Code i have now
string connString = #"Provider=Microsoft.ACE.OLEDB.16.0;Data Source=C:\Users\thoje\Desktop\stack\forslag.xlsx;" +
#"Extended Properties=""Excel 12.0;HDR=No;""";
DataTable dt = new DataTable();
string sql = #"SELECT * from [Ark1$]";
using (OleDbConnection conn = new OleDbConnection(connString))
{
conn.Open();
using (OleDbCommand cmd = new OleDbCommand(sql, conn))
{
using (OleDbDataReader rdr = cmd.ExecuteReader())
{
dt.Load(rdr);
}
}
}
DataTable dt2 = dt.Clone();
//foreach (DataRow dr in dt.Rows)
//{
for (int i = 5; i <= dt.Rows.Count-1; i++)
{
if (i == 6)
{
DataRow dr = dt2.NewRow();
dr.ItemArray = dt.Rows[i].ItemArray;
dt2.Rows.Add(dr);
}
else if(i >=8)
{
DataRow dr = dt2.NewRow();
dr.ItemArray = dt.Rows[i].ItemArray;
dt2.Rows.Add(dr);
}
}
What i need is:
I want all my data on row 6 to become headers in a new DataTable
All data after line 7 i need to append to this new Datatable with the new headers.
What my code shows:
My code now shows how to do it on a DataTable which is cloned, so therefore i have the wrong headernames.
You don't need to iterate through all rows if you only need 1 of them.
DataTable dtSource = new DataTable();
DataTable dtTarget = new DataTable();
// Get row at index == 6 (7th line as this is a 0-based-index)
var headerRow = dtSource.Rows[6];
// Iterate through all values
foreach(var value in headerRow.ItemArray)
{
// For each value create a column
// and add it to your new dataTable
DataColumn dc = new DataColumn(value.ToString());
dc.Caption = value.ToString();
dtTarget.Columns.Add(dc);
}
using a linq approach might be good:
a pseudo way:
//linq query to select row
var query = from myRow in
myDataTable.AsEnumerable() where myRow.Field<int>("RowNo") == 6
select myRow;
// Create a table from the query DataTable newTable =
query.CopyToDataTable<DataRow>();
Your question is pretty confusing to read, and keeps talking about rows where I'd expect columns etc, but I'll make the following assumptions:
You have an excel file with 5 blank rows and then a row of headers, and then data rows
You've successfully imported this data into a Datatable called dt
You want to end up with a datatable that has the values in row 6 as the column names, and the blank rows removed
Code:
for(int i = 5; i >= 0; i--){
if(i == 5)
{
for(int j = 0; j < dt.Columns.Count; j++)
dt.Columns[j].ColumnName = dt.Rows[i][j].ToString();
}
dt.Rows.RemoveAt(i);
}
You don't need to clone the datatable. Watch out for strings that make for poor column names (containing chars like '[' ) making your life miserable further down the line ..
I wrote a method for splitting a DataTable into multiple small data tables; however I am getting exception. How do I correct it? Please share the code.
Exception message:
This row already belongs to another table.
Framework: .Net 3.0
private static List<DataTable> SplitDataTable(DataTable dt, int size)
{
List<DataTable> split = new List<DataTable>();
DataTable current = dt.Clone();
int iterator = 0;
foreach (DataRow dr in dt.Rows)
{
iterator = iterator + 1;
if (iterator == size)
{
current = dt.Clone();
split.Add(current);
iterator = 0;
}
current.Rows.Add(dr);
//Exception: This row already belongs to another table.
}
return split;
}
Client:
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("TEST", typeof(int));
dt.Columns.Add("VAL", typeof(string));
dt.Rows.Add(0,"a");
dt.Rows.Add(1,"b");
dt.Rows.Add(2,"c");
dt.Rows.Add(3,"d");
List<DataTable> split = SplitDataTable(dt, 2);
}
Use dt.Copy(); instead of dt.Clone();
Before you add a DataRow to your cloned datatable, you need to remove it from the original source datatable:
foreach (DataRow dr in dt.Rows)
{
iterator = iterator + 1;
if (iterator == size)
{
current = dt.Clone();
split.Add(current);
iterator = 0;
}
dt.Rows.Remove(dr); // remove it from the source FIRST, then add it to the cloned DataTable
current.Rows.Add(dr);
}
Use current.ImportRow(dr); instead of current.Rows.Add(dr);
You can either remove the DataRow from the source DataTable or create a new DataRow and add it to the new DataTable.
You just need to change the line where you add the data row to current data table. Use the overload which takes an object array to create a new row. This way you are not cloning or copying any rows, instead creating a new row.
current.Rows.Add(dr.ItemArray);
I think this function will not work properly try this
I make some modification on you code it's working fine
private static List<DataTable> SplitDataTable(DataTable dt, int size)
{
List<DataTable> split = new List<DataTable>();
DataTable current = dt.Clone();
int iterator1 = 0;
foreach (DataRow dr in dt.Rows)
{
if (current.Rows.Count < size)
{
current.Rows.Add(dr.ItemArray);
}
if (current.Rows.Count == size)
{
iterator1= iterator1+size;
split.Add(current);
current = dt.Clone();
}
}
if (iterator1 < dt.Rows.Count) { split.Add(current); }
return split;
}
happy codding
I may well be looking at this problem backwards but I am curious none the less. Is there a way to build a DataTable from what is currently displayed in the DataGridView?
To be clear, I know you can do this DataTable data = (DataTable)(dgvMyMembers.DataSource); however that includes hidden columns. I would like to build it from the displayed columns only.
Hope that makes sense.
So I ended up trying a combination of a couple of answers as that seemed best. Below is what I am trying. Basically I am creating the DataTable from the DataSource and then working backwards based on if a column is visible or not. However, after it removes a column I get a Collection was modified; enumeration operation may not execute on the next iteration of the foreach.
I am confused as I am not trying to modify the DataGridView, only the DataTable so what's up?
DataTable data = GetDataTableFromDGV(dgvMyMembers);
private DataTable GetDataTableFromDGV(DataGridView dgv)
{
var dt = ((DataTable)dgv.DataSource).Copy();
foreach (DataGridViewColumn column in dgv.Columns)
{
if (!column.Visible)
{
dt.Columns.Remove(column.Name);
}
}
return dt;
}
Well, you can do
DataTable data = (DataTable)(dgvMyMembers.DataSource);
and then use
data.Columns.Remove(...);
I think it's the fastest way. This will modify data source table, if you don't want it, then copy of table is reqired. Also be aware that DataGridView.DataSource is not necessarily of DataTable type.
I don't know anything provided by the Framework (beyond what you want to avoid) that would do what you want but (as I suspect you know) it would be pretty easy to create something simple yourself:
private DataTable GetDataTableFromDGV(DataGridView dgv) {
var dt = new DataTable();
foreach (DataGridViewColumn column in dgv.Columns) {
if (column.Visible) {
// You could potentially name the column based on the DGV column name (beware of dupes)
// or assign a type based on the data type of the data bound to this DGV column.
dt.Columns.Add();
}
}
object[] cellValues = new object[dgv.Columns.Count];
foreach (DataGridViewRow row in dgv.Rows) {
for (int i = 0; i < row.Cells.Count; i++) {
cellValues[i] = row.Cells[i].Value;
}
dt.Rows.Add(cellValues);
}
return dt;
}
one of best solution enjoyed it ;)
public DataTable GetContentAsDataTable(bool IgnoreHideColumns=false)
{
try
{
if (dgv.ColumnCount == 0) return null;
DataTable dtSource = new DataTable();
foreach (DataGridViewColumn col in dgv.Columns)
{
if (IgnoreHideColumns & !col.Visible) continue;
if (col.Name == string.Empty) continue;
dtSource.Columns.Add(col.Name, col.ValueType);
dtSource.Columns[col.Name].Caption = col.HeaderText;
}
if (dtSource.Columns.Count == 0) return null;
foreach (DataGridViewRow row in dgv.Rows)
{
DataRow drNewRow = dtSource.NewRow();
foreach (DataColumn col in dtSource .Columns)
{
drNewRow[col.ColumnName] = row.Cells[col.ColumnName].Value;
}
dtSource.Rows.Add(drNewRow);
}
return dtSource;
}
catch { return null; }
}
First convert you datagridview's data to List, then convert List to DataTable
public static DataTable ToDataTable<T>( this List<T> list) where T : class {
Type type = typeof(T);
var ps = type.GetProperties ( );
var cols = from p in ps
select new DataColumn ( p.Name , p.PropertyType );
DataTable dt = new DataTable();
dt.Columns.AddRange(cols.ToArray());
list.ForEach ( (l) => {
List<object> objs = new List<object>();
objs.AddRange ( ps.Select ( p => p.GetValue ( l , null ) ) );
dt.Rows.Add ( objs.ToArray ( ) );
} );
return dt;
}
I have a DataView which has two columns: ContactID, and Name
How can I check if a particular ContactID is already existing in the DataView?
Have you had a look at DataView.FindRows Method or maybe DataView.Find Method
The DataView has a method called FindRows, this can be used to search for a specific contactID, for example...
var table = new DataTable();
var column = new DataColumn("Id", typeof (int));
table.Columns.Add(column);
table.PrimaryKey = new[] {column}; // Unique Constraint
var row = table.NewRow();
row["Id"] = 100;
table.Rows.Add(row);
row = table.NewRow();
row["Id"] = 200;
table.Rows.Add(row);
var view = new DataView(table) { ApplyDefaultSort = true };
var rows = view.FindRows(200);
foreach(var r in rows)
{
Console.WriteLine(r["Id"]);
}
Use the Following code to Find the row in the Dataview
//Your original Table Which consist of Data
DataTable dtProducts = new DataTable();
//Add the DataTable to DataView
DataView ProductDataView = new DataView(dtProducts);
ProductDataView.RowFilter = "";
ProductDataView.Sort = "ProdId";
int recordIndex = -1;
//In the Find Row Method pass the Column
//value which you want to find
recordIndex = ProductDataView.Find(1);
if (recordIndex > -1)
{
Console.WriteLine("Row Found");
}
How to add identity column to datatable using c#. Im using Sql compact server.
You could try something like this maybe?
private void AddAutoIncrementColumn()
{
DataColumn column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.AutoIncrement = true;
column.AutoIncrementSeed = 1000;
column.AutoIncrementStep = 10;
// Add the column to a new DataTable.
DataTable table = new DataTable("table");
table.Columns.Add(column);
}
DataTable table = new DataTable("table");
DataColumn dc= table.Columns.Add("id", typeof(int));
dc.AutoIncrement=true;
dc.AutoIncrementSeed = 1;
dc.AutoIncrementStep = 1;
// Add the new column name in DataTable
table.Columns.Add("name",typeof(string));
table.Rows.Add(null, "A");
table.Rows.Add(null, "B");
table.Rows.Add(null, "C");
If the DataTable is already populated. you can use below method
void AddAndPopulateDataTableRowID(DataTable dt, string col, bool isGUID)
{
if(isGUID)
dt.Columns.Add(col, typeof(System.Guid));
else
dt.Columns.Add(col, typeof(System.Int32));
int rowid = 1;
foreach (DataRow dr in dt.Rows)
{
if (isGUID)
dr[col] = Guid.NewGuid();
else
dr[col] = rowid++;
}
}
You don't do autoincrement on DataTable (or front-end for that matter), unless you want to make your application a single user application only.
If you need the autoincrement, just do it in database, then retrieve the autoincremented id produced from database to your front-end.
See my answer here, just change the SqliteDataAdapter to SqlDataAdapter, SqliteConnection to SqlConnection, etc : anyway see why I get this "Concurrency Violation" in these few lines of code??? Concurrency violation: the UpdateCommand affected 0 of the expected 1 records
Just my two cents. Auto-increment is useful in a Winform app (stand alone as Michael Buen rightly said), i.e.:
DatagridView is being used to display data that does not have a "key field", the same can be used for enumeration.
I dont think its a good idea to use autoincrement on datatable if you are using insert and delete to a datatable because the number will not be rearranget, no final i will share a small idea how can we use autoincrement manual.
DataTable dt = new DataTable();
dt.Columns.Add("ID",typeof(int));
dt.Columns.Add("Produto Nome", typeof(string));
dt.Rows.Add(null, "A");
dt.Rows.Add(null, "B");
dt.Rows.Add(null, "C");
for(int i=0;i < dt.Rows.Count;i++)
{
dt.Rows[i]["ID"] = i + 1;
}
always when finalizing the insert or delete must run this loop
for(int i=0;i < dt.Rows.Count;i++)
{
dt.Rows[i]["ID"] = i + 1;
}