I get an error 'this row already belongs to this table' from the following code:
public static DataTable AddNewAllocations(string pCaseNo, ref DataTable pTable)
{
try
{
string sqlText = "SELECT UserID FROM tblUsers;";
aSqlQuery aQ = new aSqlQuery(sqlText, "table");
DataTable userTable = aQ.TableResult;
foreach (DataRow userRow in userTable.Rows)
{
int allocAlready = 0;
foreach (DataRow allocRow in pTable.Rows)
{
if (allocRow["FeeEarner"].ToString() == userRow["UserID"].ToString())
{
allocAlready = 1;
}
}
if (allocAlready == 0)
{
string strUser = userRow["UserID"].ToString();
decimal fees = cTimesheet.UserFees(strUser, pCaseNo);
int intCaseNo = Int32.Parse(pCaseNo);
if (fees > 0)
{
Object[] array = new object[8];
array[0] = 0;
array[1] = intCaseNo;
array[2] = DateTime.Today;
array[3] = strUser;
array[4] = fees;
array[5] = 0;
array[6] = fees;
array[7] = true;
pTable.Rows.Add(array);
}
}
}
return pTable;
}
catch (Exception eX)
{
throw new Exception("cAllocation: Error in NewAllocations()" + Environment.NewLine + eX.Message);
}
When I step through the code I can see that the error is thrown on the second occasion the following line is accessed:
pTable.Rows.Add(array);
Given that I create a new object array each time the code enters the loop, I fail to see why I am receiving this error message, which suggests to me the same row is being added multiple times. Why does the code see each loop as adding the same datarow when the row is generated by a new object array each time?
Another approach is to create a NewRow() at the beginning of the loop, assign its data, then Rows.Add() at the bottom of the loop.
{
// initialization code
// ...
foreach (DataRow row in dt.Rows)
{
row.Delete();
}
Oda.Update(ds, "USERTABLE");
DataRow dr;
foreach (var userRecord in urList)
{
dr = dt.NewRow();
dr["username"] = userRecord.userName;
dr["firstname"] = userRecord.firstName;
dr["lastname"] = userRecord.lastName;
dr["createdon"] = userRecord.createdOn;
dt.Rows.Add(dr);
}
Oda.Update(ds, "USERTABLE");
}
The code that finally worked was this:
public static DataTable AddNewAllocations(string pCaseNo, DataTable pTable)
{
try
{
DataTable newTable = NewAllocationTable();
string sqlText = "SELECT UserID FROM tblUsers;";
aSqlQuery aQ = new aSqlQuery(sqlText, "table");
DataTable userTable = aQ.TableResult;
foreach (DataRow userRow in userTable.Rows)
{
int allocAlready = 0;
foreach (DataRow allocRow in pTable.Rows)
{
if (allocRow["FeeEarner"].ToString() == userRow["UserID"].ToString())
{
allocAlready = 1;
}
}
if (allocAlready == 0)
{
string strUser = userRow["UserID"].ToString();
decimal fees = cTimesheet.UserFees(strUser, pCaseNo);
int intCaseNo = Int32.Parse(pCaseNo);
if (fees > 0)
{
Object[] array = new object[8];
array[0] = 0;
array[1] = intCaseNo;
array[2] = DateTime.Today;
array[3] = strUser;
array[4] = fees;
array[5] = 0;
array[6] = fees;
array[7] = true;
newTable.Rows.Add(array);
}
}
}
foreach (DataRow row in pTable.Rows)
{
newTable.ImportRow(row);
}
newTable.DefaultView.Sort = "AllocID";
return newTable;
}
catch (Exception eX)
{
throw new Exception("cAllocation: Error in NewAllocations()" + Environment.NewLine + eX.Message);
}
}
I think the key was using ImportRow rather than Rows.Add. I still use Rows.Add in my method but only when adding rows to a newly created table. I then loop through the existing table which was passed in as a paramater, and use ImportRow to add each row of the paramater table, to the newly created one. I then pass the new combined table out in my return statement, rather than a modified parameter table.
Related
I am currently developing a P.O.S software and i started to code the pay form. But i want when the user enters the same product to increment the quantity value and not to display it on another row, i coded it but it displays the updated row and the products on the other rows
public void dodadi() {
MySqlConnection connection = Connection.prevzemiKonekcija();
connection.Open();
try
{
if (string.IsNullOrWhiteSpace(txtBarajKod.Text))
{
return;
}
bool Found = false;
if (dataGridView1.Rows.Count > 0)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (Convert.ToString(row.Cells[0].Value) == txtBarajKod.Text)
{
row.Cells[3].Value = Convert.ToString(1 + Convert.ToInt64(row.Cells[3].Value));
Found = true;
}
}
}
if(!Found)
{
MySqlCommand command;
MySqlDataAdapter adapter;
DataTable tabela;
MySqlDataReader reader;
string query = "SELECT * FROM artikli WHERE barcode like '%" + txtBarajKod.Text + "%'";
command = new MySqlCommand(query, connection);
adapter = new MySqlDataAdapter(command);
tabela = new DataTable();
reader = command.ExecuteReader();
//dataGridView1.DataSource = tabela;
//adapter.Fill(tabela);
if (string.IsNullOrWhiteSpace(txtBarajKod.Text))
{
return;
}
if (reader.Read())
{
txtBarajKod.Text = reader.GetString("barcode");
txtNaziv.Text = reader.GetString("ProductName");
txtCena.Text = reader.GetString("SellPrice");
kolicina = 1;
txtKolicina.Text = kolicina.ToString();
}
else
{
txtBarajKod.Text = "";
txtNaziv.Text = "";
txtCena.Text = "";
txtKolicina.Text = "";
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
connection.Close();
}
}
private void dodadivotabela() {
cena = float.Parse(txtCena.Text);
kolicina = float.Parse(txtKolicina.Text);
konecnacena = cena * kolicina;
string prvred = txtBarajKod.Text;
string vtorred = txtNaziv.Text;
float tretred = cena;
float cetvrtred = kolicina;
float pettired = konecnacena;
dataGridView1.Rows.Add(prvred, vtorred, tretred, cetvrtred, pettired);
}
this is the second method that adds the data to the dgv
If I understood clearly, you don't want the value to show on the 4th cell of the 2nd and 3rd rows when you increment the value of the first row.
If I'm right, you should add a break statement in your foreach loop like so:
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (Convert.ToString(row.Cells[0].Value) == txtBarajKod.Text)
{
row.Cells[3].Value = Convert.ToString(1 + Convert.ToInt64(row.Cells[3].Value));
Found = true;
break;
}
}
The break statement will allow you to exit your foreach loop once your condition is met for the first time. If you omit it it will loop over all the other rows and change the value in the 4th cell like in your screenshot because your condition is still met in the other rows.
UPDATED
Ok so you just need to clear your dataGridView1 before you add your updated row to it. I presume your dodadivotabela() method is called when you update the row with the incremented value. Add dataGridView1.Rows.Clear() to your method :
private void dodadivotabela()
{
cena = float.Parse(txtCena.Text);
kolicina = float.Parse(txtKolicina.Text);
konecnacena = cena * kolicina;
string prvred = txtBarajKod.Text;
string vtorred = txtNaziv.Text;
float tretred = cena;
float cetvrtred = kolicina;
float pettired = konecnacena;
dataGridView1.Rows.Clear();
dataGridView1.Rows.Add(prvred, vtorred, tretred, cetvrtred, pettired);
}
i'm new to MVC and I am trying to build a DataTable from a stored procedure response and pass it back to my View. For the rows I build a comma delimited string full of cell values.
The issue I am having is that the string is not getting parsed by the commas, and effectively it is passing the whole string into the first cell of each row.
What is the correct way to build up a row comprised of the individual values for each column? The number of columns, their names, and amount of records returned are all variable.
public ActionResult dataSet(string table, string key, string search)
{
SqlDataReader rdr = null;
SqlConnection con = new SqlConnection("Connection stuff");
SqlCommand cmd = new SqlCommand();
cmd = new SqlCommand("dbo.USP_getDataSet", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#key", key);
cmd.Parameters.AddWithValue("#table", table);
cmd.Parameters.AddWithValue("#search", search);
con.Open();
DataTable theTable = new DataTable();
try
{
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
int count = rdr.FieldCount;
string rowString = "";
int intRows = theTable.Columns.Count;
//Build columns on first pass through
if (intRows == 0){
for (int i = 0; i < count; i++){
theTable.Columns.Add(Convert.ToString(rdr.GetName(i).TrimEnd()), typeof(string));
}
}
//Grab all values for each column
for (int i = 0; i < count; i++){
rowString += '\"' + (Convert.ToString(rdr.GetValue(i)).TrimEnd()) + '\"' + ", ";
}
//Remove trailing delimiter
string finishedRow = rowString.Substring(0, rowString.Length - 2);
//Add the full row for each time through reader
theTable.Rows.Add(finishedRow);
}
}
finally
{
if (rdr != null)
{ rdr.Close(); }
if (con != null)
{ con.Close(); }
}
return View(theTable);
}
According to the documentation for the DataRowCollection.Add(params Object[] values) method, each value passed in will populate each cell. Since you are passing in a single value, it is the value of the cell.
You probably want:
var cells = new object[count];
for (int i = 0; i < count; i++)
{
cells[i] = rdr.GetString(i).Trim() + "\"
}
theTable.Rows.Add(cells)
I have 2 DataTable
string query = "Select * from " + ServerTableName;
DataTable oDtSeverData = GetDataTable(query);
string dbQuery = "SELECT * from " + LocalSystemTableName;
DataTable oDtLocalSystemData = dataService.GetDataTable(dbQuery);
I want to compare(Row and Column) both the datatable, to get same column(exist in both the datatable) with Unique records(unique Row).
Let me explain in details:
oDtServerData have columns (Column1, Column2, Column3, Column4) with few rows.
oDtLocalSystemData have columns (Column1, Column2, Column3) with few rows.
it is possible that oDtServerData can have less columns and oDtLocalSystemData. but in any case I want the column (Column1, Column2, Column3) which is matching in both the datatable with unique rows(data should be unique).
Someone please help me in this and give me some idea with few examples to solve my problems.
you can use the below code to compare two DataTable,
public static DataTable CompareTwoDataTable(DataTable dt1, DataTable dt2)
{
dt1.Merge(dt2);
DataTable d3 = dt2.GetChanges();
return d3;
}
For more information about DataTable.Merge(), please refer to DataTable.Merge Method (DataTable) on MSDN.
ArrayList commonColumns = new ArrayList();
for (int iServerColumnCount = 0; iServerColumnCount < oDtSeverData .Columns.Count; iServerColumnCount ++)
{
for (int iLocalColumnCount = 0;
iLocalColumnCount < oDtLocalSystemData .Columns.Count;
iLocalColumnCount ++)
{
if (oDtSeverData .Columns[iServerColumnCount ].ColumnName.ToString()
.Equals(oDtLocalSystemData .Columns[iLocalColumnCount].ColumnName.ToString()))
{
commonColumns.Add(oDtLocalSystemData .Columns[iLocalColumnCount].ColumnName.ToString());
}
}
}
DataTable oDtData = CompareTwoDataTable(oDtLocalSystemData, oDtSeverData,commonColumns);
public DataTable CompareTwoDataTable(DataTable dtOriginalTable, DataTable dtNewTable, ArrayList columnNames)
{
DataTable filterTable = new DataTable();
try
{
filterTable = dtNewTable.Copy();
string filterCriterial;
if (columnNames.Count > 0)
{
for (int iNewTableRowCount = 0; iNewTableRowCount < dtNewTable.Rows.Count; iNewTableRowCount++)
{
filterCriterial = string.Empty;
foreach (string colName in columnNames.ToArray())
{
filterCriterial += "ISNULL("+colName.ToString() + ",'')='" + dtNewTable.Rows[iNewTableRowCount][colName].ToString() + "' AND ";
}
filterCriterial = filterCriterial.TrimEnd((" AND ").ToCharArray());
DataRow[] dr = dtOriginalTable.Select(filterCriterial);
if (dr.Length > 0)
{
filterTable.Rows[filterTable.Rows.IndexOf(filterTable.Select(filterCriterial)[0])].Delete();
filterTable.AcceptChanges();
}
}
}
}
catch (Exception ex)
{
}
return filterTable;
}
I was trying to insert data to table to I used bulk insert for that i used same common column
public bool BulkInsertDataTable(string tableName, DataTable dataTable, string[] commonColumns)
{
bool isSuccuss;
try
{
SqlConnection SqlConnectionObj = GetSQLConnection();
SqlBulkCopy bulkCopy = new SqlBulkCopy(SqlConnectionObj, SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers | SqlBulkCopyOptions.UseInternalTransaction, null);
bulkCopy.DestinationTableName = tableName;
bulkCopy.ColumnMappings.Clear();
for (int iDtColumnCount = 0; iDtColumnCount < dataTable.Columns.Count; iDtColumnCount++)
{
for (int iArrCount = 0; iArrCount < commonColumns.Length; iArrCount++)
{
if (dataTable.Columns[iDtColumnCount].ColumnName.ToString().Equals(commonColumns[iArrCount].ToString()))
{
bulkCopy.ColumnMappings.Add(dataTable.Columns[iDtColumnCount].ColumnName.ToString(),
commonColumns[iArrCount].ToString());
}
}
}
bulkCopy.WriteToServer(dataTable);
isSuccuss = true;
}
catch (Exception ex)
{
isSuccuss = false;
}
return isSuccuss;
}
Sir I have filled my dataset with linq as
public void FillDataSet(DataSet ds1,int Id)
{
try
{
var y = from ins in cstmrDC.customers_rd(Id) select ins;
var z = from ins in cstmrDC.customersCntcts_rd(Id) select ins;
DataTable dtCst = new DataTable("dtCstmr");
dtCst.Columns.Add("cst_Id");
dtCst.Columns.Add("cst_Name");
dtCst.Columns.Add("cst_SName");
dtCst.Columns.Add("cst_AdLn1");
DataTable dtDtls = new DataTable("dtDtails");
dtDtls.Columns.Add("cst_SrlNo");
dtDtls.Columns.Add("cst_CntName");
dtDtls.Columns.Add("cst_cntDsgn");
foreach (var dtbl in y)
{
DataRow dr;
dr = dtCst.NewRow();
dr[0] = dtbl.cust_Id;
dr[1] = dtbl.cust_Name;
dr[2] = dtbl.cust_Sname;
dr[3] = dtbl.cust_Adrsln1;
dtCst.Rows.Add(dr);
}
foreach (var dtbl in z)
{
DataRow drDtls;
drDtls = dtDtls.NewRow();
drDtls[0] = dtbl.cust_Slno;
drDtls[1] = dtbl.cust_Cntctnm;
drDtls[2] = dtbl.cust_Cntctdesig;
dtDtls.Rows.Add(drDtls);
}
ds1.Tables.Add(dtCst);
ds1.Tables.Add(dtDtls);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and the Id is passing from another class as
intId = int.Parse(txtSearch.Text);
cstCls.FillDataSet(ds1w, intId);
from that dataset iam fillimg my textbox controllers and giving theDataSource to the dataGridView as
dgvCustInfo.DataSource = ds1w.Tables["dtDtails"];
In this way if I searched 1st time with integer id 1055 meanse the exact result is comming from database. At the same time If I gave the another integer Id as 1066 meance Iam getting exception as DataTable named 'dtCstmr' already belongs to this DataSet .. Soo how can I solve the problem.
You can check if a table is already contained in a DataSet with Contains:
if(!ds1.Tables.Contains(dtCst.TableName))
ds1.Tables.Add(dtCst);
if(!ds1.Tables.Contains(dtDtls.TableName))
ds1.Tables.Add(dtDtls);
However, as Raphael has mentioned this would not refresh the table in the DataSet. So an easy way would be to remove the old table and add the new:
if(ds1.Tables.Contains(dtCst.TableName))
ds1.Tables.Remove(dtCst.TableName);
if(ds1.Tables.Contains(dtDtls.TableName))
ds1.Tables.Remove(dtDtls.TableName);
ds1.Tables.Add(dtCst);
ds1.Tables.Add(dtDtls);
It's quite a bad idea to create and populate in the same method.
Your code is really confusing.
Create another method :
public void CreateTables(DataSet ds1) {
var dtCst = new DataTable("dtCstmr");
dtCst.Columns.Add("cst_Id");
dtCst.Columns.Add("cst_Name");
dtCst.Columns.Add("cst_SName");
dtCst.Columns.Add("cst_AdLn1");
var dtDtls = new DataTable("dtDtails");
dtDtls.Columns.Add("cst_SrlNo");
dtDtls.Columns.Add("cst_CntName");
dtDtls.Columns.Add("cst_cntDsgn");
ds1.Tables.Add(dtCst);
ds1.Tables.Add(dtDtls);
}
public void FillDataSet(DataSet ds1,int Id)
{
try
{
var y = from ins in cstmrDC.customers_rd(Id) select ins;
var z = from ins in cstmrDC.customersCntcts_rd(Id) select ins;
var dtCst = ds1.Tables["dtCstmr"];
var dtDtls = ds1.Tables["dtDtails"];
dtCst.Clear();
dtDtls.Clear();
foreach (var dtbl in y)
{
DataRow dr;
dr = dtCst.NewRow();
dr[0] = dtbl.cust_Id;
dr[1] = dtbl.cust_Name;
dr[2] = dtbl.cust_Sname;
dr[3] = dtbl.cust_Adrsln1;
dtCst.Rows.Add(dr);
}
foreach (var dtbl in z)
{
DataRow drDtls;
drDtls = dtDtls.NewRow();
drDtls[0] = dtbl.cust_Slno;
drDtls[1] = dtbl.cust_Cntctnm;
drDtls[2] = dtbl.cust_Cntctdesig;
dtDtls.Rows.Add(drDtls);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Method CreateTables should be called only one time, and FillDataSet as many times as needed.
I need to insert values in a table that have different columns from time to time. The columns and row data are updated from MySql. Each row values are in single MySql cells with the following format:
ColumnName{Delimiter}Value{BigDelimiter}Column2Name{Delimiter}Value2...
So I split the cell strings to get the column header and value, as the user can rearrange columns, modify, delete or insert new ones. I searched for a solution, though I get nothing but empty rows:
private void GetDataTableValues()
{
if (dtData.Value != null)
{
try
{
LoadFields();
dgwDataMain.Items.Clear();
dgwDataMain.Columns.Clear();
foreach (Fields field in fields)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = field.name;
column.Binding = new Binding(field.name);
dgwDataMain.Columns.Add(column);
}
if (connection.State == System.Data.ConnectionState.Broken || connection.State == System.Data.ConnectionState.Closed)
connection.Open();
command.Parameters.Clear();
DateTime dt = dtData.Value ?? DateTime.Now;
command.Parameters.Add("#date", MySqlDbType.Date, 50).Value = dt.ToString("yyyy-MM-dd");
command.CommandText = "SELECT value,team FROM sessions WHERE date=#date";
List<string> teams = new List<string>();
foreach (Control ctrl in panDataFilter.Children)
if ((ctrl as CheckBox).IsChecked == true)
teams.Add(Convert.ToString((ctrl as CheckBox).Content));
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
bool v = false;
if (teams.Contains(reader[1].ToString()) || teams.Count == 0)
v = true;
if (v)
{
DatabaseObject obj = new DatabaseObject();
List<string> str2 = new List<string>(reader[0].ToString().Split(new string[] { "</s&p>" }, StringSplitOptions.None).ToList());
obj.Items = new List<string>(str2.Count);
foreach (string str in str2)
{
List<string> item = new List<string>(str.Split(new string[] { "<&p>" }, StringSplitOptions.None).ToList());
int index = dgwDataMain.Columns.Single(c => c.Header.ToString() == item[0].ToString()).DisplayIndex;
obj.Items.Insert(index, item[1].ToString());
}
dgwDataMain.Items.Add(obj);
}
}
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.ErrorCode.ToString() + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
}
}
public class DatabaseObject
{
public List<string> Items = new List<string>();
}
to delete extra row from datagrid is, just make property...
Canuseraddrows="false";
Please use Observablecollection to bind the data grid. By using observablecollection easily you can add or delete item and not required to reset the data source of data grid.
Sample Code:
observableCollection myClass = new
observableCollection();
myClass.add(Class)