Can't select DataRow from DataTable - c#

I'm trying to prevent inserting duplicated data into MS Access table like below,
MS Access table(Record) with Columns: Situation, Check_Item, and starts with no data in the table.
DataTable from DataSet is filled with the query "SELECT * FROM Record WHERE Situation = 'A'".
Then I try to do this process,
DataRow = DataTable.Select("Check_Item = '"+InputTextBox.Text"'");
If (DataRow.Length == 0)
{
Use OleDbCommand to insert InputTextBox.Text string to Check_Item of Record table.
}
Result:
First time key in(e.g. 123456), because there is no data in the table, so 123456 is inserted into Record table.
But at the second time key in 123456, then it still be inserted into Record table.
What happened in this process??

Assuming your DataTable variable has name table, and that you created it and linked it correctly to your MS Access database then:
DataRow[] rows = table.Select("Check_Item = '"+InputTextBox.Text"'"); //Selects all rows where the condition is met.
If (rows.Length == 0)
{
//No row met the condition so create a new one and add it to the table.
DataRow newRow = table.NewRow(); //Creates a new row with the same schema (columns) as the table.
newRow["Check_Item"] = InputTextBox.Text; //Assigns the value.
table.Rows.Add(newRow); //Adds the new row to the row collection of the table.
table.AcceptChanges(); //Commits and persist the changes done to the table.
}
Be sure to check this and also the official docs for DataTable.

Related

How would I filter this dataset?

I have a dataset that looks like the image. I'm trying to filter by table and get all the columns next to it and compare them against other datasets
This dataset has tables named table 1 and table 2 and when they're selected they look like the picture below. It shows the columns and I need to compare those columns against the rows from the matching table in the first dataset
I've looked at dataview but that would be a lot of work and I'm very inexperienced. I'm trying to find a way to implement a foreach loop that'll get the name of the table in the first dataset and then compare the rows in it against the columns inside the datatable in the second dataset that matched the table name from the first dataset.
Without knowing more about these DataSets (like do they have primary keys, the data types of the columns, the number of rows in each table, etc), I can only provide limited help. The following example tries to be as general as possible and avoid some basic problems:
DataSet ds1 = <<fetch dataset1>>;
DataSet ds2 = <<fetch dataset2>>;
foreach (DataTable tbl1 in ds1.Tables)
{
if (ds2.Tables.Contains(tbl1.TableName))
{
DataTable tbl2 = ds2.Tables[tbl1.TableName];
List<string> commonColumnNames = new List<string>(tbl1.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Intersect(tbl2.Columns.Cast<DataColumn>().Select(c => c.ColumnName)));
int maxRows = Math.Min(tbl1.Rows.Count, tbl2.Rows.Count);
for (int r = 0; r <= maxRows; r++)
{
foreach (string colName in commonColumnNames)
{
if (tbl1.Rows[r][colName] != tbl2.Rows[r][colName])
{
// Different value
}
}
}
}
}
Update 1: I've added comments to the following example to explain step-by-step what this code is doing. As I try to say before, since I didn't know much about your data, I had to put in extra code. This extra code is for things like: 'Does the table ABC exist in both DataSets?', 'Do the two tables have the same columns in them?', 'Do the tables have the same number of rows in them?'. Your original question did not have this information, so I made this code a little more robust to handle those unknowns.
DataSet ds1 = <<fetch dataset1>>;
DataSet ds2 = <<fetch dataset2>>;
// Loop through all of the tables in the 1st DataSet
foreach (DataTable tbl1 in ds1.Tables)
{
// If the 2nd DataSet has a table with same name as the one from the 1st DataSet
if (ds2.Tables.Contains(tbl1.TableName))
{
DataTable tbl2 = ds2.Tables[tbl1.TableName];
// Create a list of column names that the two tables have in common.
// We will only compare the values in these two tables, in this set of matching column names.
List<string> commonColumnNames = new List<string>(tbl1.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Intersect(tbl2.Columns.Cast<DataColumn>().Select(c => c.ColumnName)));
// Before we start comparing the rows in the two tables, find out which one has the fewer number of rows in it.
int maxRows = Math.Min(tbl1.Rows.Count, tbl2.Rows.Count);
// If the tables have a different number of rows, then we will only compare the set of rows numbered 0-to-MinRowCount
for (int r = 0; r <= maxRows; r++)
{
// For each row, compare the values of common columns
foreach (string colName in commonColumnNames)
{
if (tbl1.Rows[r][colName] != tbl2.Rows[r][colName])
{
// Different value
}
}
}
}
}

More efficient delete of Sql table from DataTable by identifier

I have to insert-delete a Sql table using a C# DataTable. My two strategies are
delete one row at a time, or
throw the DataTable into a stored procedure and do delete where exists.
Neither strategy is preferred to me as #1 is inefficient and #2 requires some setting up (user schemas, stored procedure, etc.).
Is there another (better) way?
//place buy_detail_id into distinct datatable
DataView view = new DataView(table);
DataTable distinctIds = view.ToTable(true, "buy_detail_id");
//strategey 1: delete one row at a time by Id
foreach (DataRow row in distinctIds.Rows)
{
//delete one row at a time
DeleteRow(row[0]);
}
//strategy 2: throw DataTable into a stored proc as parameter
//then delete where buy_detail_id exists in distinctIds

dataGridView population from dataSet

I cannot get my dataGridView to update with all the tables in the dataSet. I just get one row in the dataGridView after I try to populate it.
I call this to fill my dataSet:
DataTable table = new DataTable(DateTime.Now.ToString());
table.Columns.Add("c1");
table.Columns.Add("c2");
table.Columns.Add("c3");
table.Columns.Add("c4");
table.Columns.Add("c5");
table.Columns.Add("c6");
table.Columns.Add("c7");
table.Rows.Add("s1", "s2", "s3", "s4", "s5", "s6", "s7");
dataSet1.Tables.Add(table);
dataSet1.WriteXml("MyData.xml");
The data is written fine, but if I try to read it with this I only get one row populated, even if there's multiple entries in the dataSet.
dataSet1.ReadXml("MyData.xml");
MessageBox.Show((dataSet1.GetXml()));
I get the message with the data in the correct format, with the correct number of entries.
dataGridView2.AutoGenerateColumns = true;
int i2 = 0;
while (i2 < dataSet1.Tables.Count)
{
dataGridView2.DataSource = dataSet1.Tables[i2];
i2++;
}
After this it will only show one row and not the amount of tables. The dataSet1.Tables.Count >= 2, but still only get 1 row.
Edit: It seems that each time I call this line:
dataGridView2.DataSource = dataSet1.Tables[i2];
It is deleting the previous row. Is there any way to append the row instead?
You only created one table in the data set, so your while statement only executes once:
while (i2 < dataSet1.Tables.Count)
{
...
}
Count = 1 (number of tables) because you only called dataSet1.Tables.Add(table); one time.
dataSet1.WriteXml("MyData.xml") is only writing out the schema for that single table. So reading it back in will only read back in a single table's worth of schema.
The following code appears to count the number of tables in the dataset:
while (i2 < dataSet1.Tables.Count)
Try pointing this to the table:
dataSet1.Tables["Yourtable"].Count

Appending DataRow to DataTable filled from DataAdapter, clears all records

I have a DataGridView that has a DataTable bound to it, populated from PostgreSQL database with Npgsql .NET data provider library.
Populating records works, but when I want to append just a single records to already existing DataTable, previous records vanish:
NpgsqlDataAdapter npDataAdapterSingle = new NpgsqlDataAdapter("SELECT * from \"Weight\" ORDER BY id DESC LIMIT 1", this.npConnection);
DataTable tmpTable = new DataTable("tmpTable");
npDataAdapterSingle.Fill(tmpTable);
DSWeight.WeightRow row = this.dSWeight.Weight.NewWeightRow();
row.ItemArray = tmpTable.Rows[0].ItemArray;
this.dSWeight.Weight.Rows.InsertAt(row, 0); //Prepend, but i also tried this.dsWeight.Weight.Rows.Add(row);
If I select all records, without LIMIT'ing, then it works as expected. But I thought - why would i need to query the database all over again if I already have those records? That's why I want to LIMIT.
Maybe there is another solution, because I manually add new records to database and query them to add them to datatable, not the way it is supposed to be: add new records to datatable and them to database. I do it this way because I want the database to manage the id and timestamp fields and have datagridview to have these fields populated.
What am I missing?
Am not sure about the data type of DSWeight.WeightRow and the scope of 'this' object since I get to see only a portion of the code and not the full method. This should probably work for you. please have a try.
NpgsqlDataAdapter npDataAdapterSingle = new NpgsqlDataAdapter("SELECT * from \"Weight\" ORDER BY id DESC LIMIT 1", this.npConnection);
DataTable tmpTable = new DataTable("tmpTable");
npDataAdapterSingle.Fill(tmpTable);
row = tmpTable.NewRow();
foreach (DataColumn col in tmpTable.Columns)
row[col.ColumnName] = tmpTable.Rows[0][col.ColumnName];
tmpTable.Rows.Add(row, 0);

Autonumber and datatable with dbnull exception

i was doing some work on a datatable i filled with a oledbdataadapter made from an access database. and i stumbled upon this error:
Turns out that my table has this structure:
ID --> autonumber(PK)
lazos_>text
Asociaciones->text
and when i fill my datatable all values pass to it without any problems with all the correct values. I insert a new row like shown on the "insert row" part.
i do this asumming that my pk will instert the "autonumber" on row creation, but apparently it is not doing it because when i loop trought the rows i get a "invalid cast exception" with a Object cannot be cast from DBNull to other types."
I COULD insert an id value to the column, but when i update my dt to my database wont it create an error, because i have no way of knowing wich was the last row created?, or do i?
for example lets say in my datatable the last ID is 50, but on the database y previously made a record with id "51" but then erased it, if i inserted 51 based on my dt info, it would give an error right?
//// INSERT ROW
DataRow newRow = Tabla_Cods_Proy.NewRow();
newRow["Lazos"] = textBox1.Text ;
newRow["Asociaciones"] = textBox2.Text;
Tabla_Cods_Proy.Rows.Add(newRow);
MessageBox.Show("Enhorabuena!");
//CHECK ID's
for (int i = 0; i < Tabla_Cods_Proy.Rows.Count; i++)
{
if (Tabla_Cods_Proy.Rows[i].RowState != DataRowState.Deleted)
{
if (Tabla_Cods_Proy.Rows[i]["Lazos_asociados"].ToString() == "")
{
listBox7.Items.Add(Tabla_Cods_Proy.Rows[i]["Cod_Cliente"]);
listBox8.Items.Add(Tabla_Cods_Proy.Rows[i]["Cod_Inelectra"]);
ID_Cods_Proy_Sin_Asociar.Add(Convert.ToInt32(Tabla_Cods_Proy.Rows[i]["ID"]));
}
else
{
listBox3.Items.Add(Tabla_Cods_Proy.Rows[i]["Cod_Cliente"]);
listBox4.Items.Add(Tabla_Cods_Proy.Rows[i]["Cod_Inelectra"]);
ID_Cods_Proy_Asociados.Add(Convert.ToInt32(Tabla_Cods_Proy.Rows[i]["ID"]));
}
}
I had once similiar problem. What you need to do is that you retrieve the new identity ##IDENTITY of this column once you insert it into table. You can do that by using RowUpdated event.
Here is quick example from MSDN page (similiar to your case, see bottom of the page):
public static void Main()
{
//...connecting to access db and getting data to datatable...
// ...
// Adding a new row to datatable.
DataRow newRow = catDS.Tables["Categories"].NewRow();
newRow["CategoryName"] = "New Category";
catDS.Tables["Categories"].Rows.Add(newRow);
// Include an event to fill in the Autonumber value.
catDA.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
}
protected static void OnRowUpdated(object sender, OleDbRowUpdatedEventArgs args)
{
// Include a variable and a command to retrieve the identity value from the Access database.
int newID = 0;
OleDbCommand idCMD = new OleDbCommand("SELECT ##IDENTITY", nwindConn);
if (args.StatementType == StatementType.Insert)
{
// Retrieve the identity value and store it in the CategoryID column.
newID = (int)idCMD.ExecuteScalar();
args.Row["CategoryID"] = newID;
}
}

Categories