Datagridview-multiple tables to single table - c#

I have used full join to populate my datagridview with the contents of two tables, now I want to save the contents of the datagridview into a single table.
I don't want to use loops and I don't wanna access single cells of the datagridview.
Now anyone has a solution for this ?
and using datasource of the datagridview and its adapter is not the solution,so please reply honestly after understanding my problem.

How about using your full join to populate the Third Table, then bind the third table to the DataGridView, therefor when you make changes to the DataGridView the third table is updated automatically
try this. I created a new winforms project, i added a button and a datgridview. I created a public datatable and gave it columns and a row in the Form1 constructor. When you click the button it displays the number of rows contained in the datatable. So I run the program click the button MessageBox says 1 I add a row to the datagrid view and click the button Messagebox says 2
//public/Global datatable
public DataTable myTable = new DataTable();
public Form1()
{
InitializeComponent();
//create myTable Columns
myTable.Columns.Add("Name");
myTable.Columns.Add("Age");
myTable.Columns.Add("Number");
//add one row
myTable.Rows.Add(new object[] {"myName","myAge","myNumber"});
bind to the datagridview
dataGridView1.DataSource = myTable;
}
private void button1_Click(object sender, EventArgs e)
{
//display the number or rows in the datatable
MessageBox.Show(myTable.Rows.Count.ToString());
}
}

I'm not sure I understand what you're asking for, but I will attempt to be of service. You are obtaining a result set that combines two tables using a full join, and then want to output that result set into a third table? Is that correct?
First, I would recommend creating a view for this third table. That is probably the most efficient and dynamic solution. If you want to present that data to your users, have the datagrid bind to the view. If you made any changes to the two original tables, you would have to update the third "by hand". A view does this automatically.

Related

Saving unbound column in datagridview to a datatable

Hello I have not much experience in programming and haven't found any useful information regarding my question, that's why I need your help.
My goal is to create a datagridview that is databound by a local database (datatable), which is fully customazible by user. At first, when the user logins to main form if there was no previuos instance of editing, the datagridview will display nothing, however user can add columns by button (which specifies headertext, datatype and so on) and when added the datagridview will display the first column and then the user can edit the rows simply by clicking on the datagridview square (like MS excel). After that, the user can save the data by clicking on a save button, now the datatable will show the saved data, and the next time user will login, it will show the saved contents.
The situaton of now: I have 3 columns with data in the datatable, it is databounded to the datagridview and on debug it will show how it should be, I create the unbound column but it of course will not save after pressing the save button, thats because I have a problem with this code:
private void button3_Click(object sender, EventArgs e) // save button
{
for (int j = 0; j < dataGridView1.ColumnCount; j++)
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
cmd = new SqlCommand(#"INSERT INTO Inventorius VALUES ('" +
dataGridView1.Rows[i].Cells[j].Value + "')");
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
I'm trying to find a specific algorithm that can insert all rows and columns to the datatable that are created/deleted in the datagridview.
I think I should also look into my function that adds the column, or is it irrelavent? Ah please do tell me if the goal is suitable in doing with datagridview, or is there any more better alternatives, thank you.
I think you're going about this the wrong way
I understand you want to provide the user the ability to create columns, but there are only a certain number of columns and what columns they are is dictated by the database design. You can't let the user arbitrarily add their own column (well.. you can but this seems to be not your goal)
Because there are a set of known columns you might as well just support them all, bind them all, have them all in your datagridview and then just make them all invisible (theColumn.Visible = false) and when the user chooses to "add" them, just make them Visible=true. They "look" like theyve been added but in reality they were always there, wired up and working properly, just hidden
I also think you're going about your data grid/table/access the wrong way (or, the hard way)
Add a new dataset to your project
Open it, right click the surface, add a tableadapter
Go through the wizard, selecting a connection string, saving it, adding a select that returns rows, select * from sometable where id = #id, call the methods FillBId/GetDataById, finish
Save the dataset
Switch to your form, open the Data Sources window (View menu, Other Windows), drag the node representing your datatable, onto the form - a datagridview appears along with some other componentry that will retrieve and save data, manage current rows etc
Put some code into the constructor after InitializeComponent():
foreach(DataGridViewColumn c in yourDataGridViewName.Columns)
c.Visible = false;
Wire up some way for the user to choose columns, perhaps a listbox with checkboxes that gets its items list from the datagridview columns collection
Pay attention to how the back end code is structured - when you dropped the grid on the form it writes some code too; that's how to load (fill) and save (tableadapter.update) the db too
Do not iterate over a datagridview pulling values out of it; it's a UI control for showing and editing the datatable to which it is bound. If you want to get access to values, get it via the datatable. If you want to save edited alues, it's just a single line of code: someTableAdapter.Update(someDataTableNameHere)

C# : Resetting DataGridView for new DataTable

Ok so I'm trying to make a simple SQL CE Viewer application just to view my local databases for another application, I have it setup so that I can select what database I want to open and then it automatically populates a combo box with all of the tables in the database. When I select a table it populates a DataGridView with the records in the table.
My problem is switching between tables. I can't seem to get the DataGridView to remove everything from the previous table and re-populate the DataGridView with the new table information. Of course each table has different columns and rows and such.
I've googled and searched on here and every suggestion I find doesn't seem to work. It populates the DataGridView with the first table just fine, but when I select another it basically adds the columns and rows into whatever was there....
How can I get the DataGridView to completely clear for new data?
And please don't tell me to use dataGridView1.DataSource = null; tried that, doesn't work.
Well, I checked it in one of my programs and just changing DataSource property is working fine. I didn't have to use datagridview.Refresh(). Maybe it depends on the kind of DataSource, which you are using to set datagridview data?
Write this line after you have done populating the DataSource with the new data
dataGridView1.Refresh();
You don't need to clear the DataGridView directly. Its always handled by modifying the DataSource of the DataGridView.
If there is nothing else in the form, you can simply call InitializeComponent() again. But I think #Josh is right.

DataGridview master/detail large tables

I have two tables with a master-child relation which have few million records. I'm using a typed dataset generated by visual studio. Since my tables are very large and I don't want to implement Virtual mode, I've modified the master table with a SELECT TOP X, to limit the number of rows seen, sorted by internal criteria. Now the problem with the child table is that it still brings the million rows on application startup.
What is the solution of still using the generated DataSet and limit the child DataGridView from loading all data ? The first solution that comes in my mind is to manually implement the SqlDataAdapter data filling for the child rows in an event for row selectin changed in master DataGridView. That seems to only load on demand.
Since there was no response so far, here is the quickest solution I could find:
Keep your current typed dataset and table adapters added
Add a FillBY method to your child tableAdapter using the dataset designer. Example here
Remove from the Form_Load event the call to child tableAdapter Fill() method which was bringing all your database results there
Create a handler for CurrentChanged event of your generated bindingSource for the master table and add it in the form Load event.
Should be something like this:
this.myMasterTableBindingSource.CurrentChanged += new EventHandler(myMasterTableBindingSource_CurrentChanged);
Fill your child dataGridView with the info based on the selected item in master table:
void myMasterTableBindingSource_CurrentChanged(object sender, EventArgs e)
{
DataRowView selectedRow = myMasterTableBindingSource.Current as DataRowView;
if (selectedRow != null && !selectedRow.IsNew)
{
this.myChildTableTableAdapter.FillByUser(this.myDataSet.MyChildTable, (int)selectedRow["UserID"]);
}
}

Table created dynamically and DataGridView

In my windows form I have to create a table (at runtime) of specified by the user name (in textbox) and then use this table as datasource of DataGridView. Finally, the filled table must be inserted into the database. I tried to solve this problem in two ways:
I have created a DataTable, specified its columns etc. but I couldn't insert the DataTable into the database, even using SqlDataAdapter.Update() - propably I misused DataAdapter. I'm working with C# for 1 week and I don't fully understand the idea of DataSets, TableAdapters etc. So I decided to use SQL commands.
Using ExecuteNonQuery() I've created table in my database, then I recognized, that I have to use magic SqlDataAdapter and I gave up.
I want to manage the content of DataGridView in the same way, as in the case of DataTable added to DataSet using configuration wizard.
I know, that I can skip DataGridView, create list of textboxes, button expanding this list, and function inserting all fields into my table after confirmation button, but my supervisor expects DataGridView.
I can't paste the code here, because I left only copy of source code on company computer. If it will be necessary I will paste here my code tomorrow.
try to use the method either RowValidating or CellValidating of DataGridView
private void dataGridViewEnterTab1_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
if (dataGridViewEnterTab1.IsCurrentRowDirty) // Trigger when the row is dirty or has changed
{
string userName = dataGridViewEnterTab1["UserNameCol", e.RowIndex].EditedFormattedValue.ToString();
//...Your SqlDataAdapter or codes
}
}
I hope it will help this idea. :)

optimize updates to DataTable bound to DataGridView

I have a Form in my application that displays some data. When I first show the Form, I load some data into a DataTable then bind the DataTable to a DataGridView. I also start an asynchronous method that executes some slower database queries. When these slow queries complete, I need to update a few hundred rows in the DataTable, filling in values returned from the slower queries, like so:
foreach (DataRow row in data.Rows)
{
SlowLoadingData slow_stuff = slow_query_results[(int)row["id"]];
row.BeginEdit();
row[column_one] = slow_stuff.One;
row[column_two] = slow_stuff.Two;
row[column_three] = slow_stuff.Three;
row.EndEdit();
}
This is extremely slow, hanging the UI thread for a minute or more, presumably because each row is triggering a redraw.
After some research, I found a way to make it fast. First, bind the DataGridView to a BindingSource that is bound to the DataTable, instead of directly to the DataTable. Then, do as follows when you make changes to the DataTable:
binding_source.SuspendBinding();
binding_source.RaiseListChangedEvents = false;
// foreach (DataRow in Data.Rows) ... code above
binding_source.RaiseListChangedEvents = true;
binding_source.ResumeBinding();
grid.Refresh();
There is a problem, though, and it's a doozy: the code above prevents the DataGridView from detecting new rows added to the DataTable. Any new rows added to the table do not appear in the grid. The grid may also throw exceptions if you use the arrow keys to move the current cell selection off the bottom end of the grid, because the underlying data source has more rows but the grid has not created grid rows to display them.
So, two possible solutions that I can see:
Is there a better way to suppress binding updates while making changes to the underlying DataTable?
Is there an easy way to tell the DataGridView to gracefully refresh its grid row collection to match the number of underlying DataTable rows? (Note: I've tried calling BindingSource.ResetBindings, but it seems to trigger more exceptions if you have removed rows from the DataTable!)
You can try using the Merge method on the DataTable. I'll try to create a simple demo app and post it here, but the idea is simple. When you want to update the Grid, query the results into a new DataTable, and then merge the old table with the new table. As long as both tables have primary keys (you can create them them im memory if they don't come back from the DB) then it should track changes and update the DataGridView seamlessly. It also has the advantage of not losing the users place on the grid.
OK, here's a sample. I create a form with two buttons and one dataGridView. On button1 click, I populate the main table with some data, and bind the grid to it. Then, on second click, I create another table with the same schema. Add data to it (some that have the same primary key, and some that have new ones). Then, they merge them back to the original table. It updates the grid as expected.
public partial class Form1 : Form
{
private DataTable mainTable;
public Form1()
{
InitializeComponent();
this.mainTable = this.CreateTestTable();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
this.mainTable.Rows.Add(String.Format("Person{0}", i), i * i);
}
this.dataGridView1.DataSource = this.mainTable;
}
private void button2_Click(object sender, EventArgs e)
{
DataTable newTable = this.CreateTestTable();
for (int i = 1; i <= 15; i++)
{
newTable.Rows.Add(String.Format("Person{0}", i), i + i);
}
this.mainTable.Merge(newTable);
}
private DataTable CreateTestTable()
{
var result = new DataTable();
result.Columns.Add("Name");
result.Columns.Add("Age", typeof(int));
result.PrimaryKey = new DataColumn[] { result.Columns["Name"] };
return result;
}
}
Have you considered disconnecting the dataGrid or the bindingSource while filling the table and reconnecting afterwards? It might look a bit ugly, but it should be a lot faster.
If you're using a BindingSource for complex data binding, it's important to understand that SuspendBinding and ResumeBinding only suspend and resume binding for the current item. This lets you disable binding for the current item and change a bunch of its properties without any of the individual changes to the property being pushed out to the bound control. (This isn't explained in the documentation for the BindingSource, where it would be useful, oh no: it's in the documentation for the CurrencyManager.)
Any changes you make to the other items in the list, i.e. everything except the current item, raise the ListChanged event. If you disable these events, the BindingSource stops telling the bound control about changes to the list until you re-enable them. This has the result you've seen: you add all of your rows to the underlying DataTable, but since you've turned ListChanged events off, the BindingSource doesn't tell the DataGridView about them, and so the DataGridView remains empty.
The proper solution is to call ResetBindings, which forces the BindingSource to refresh all of the controls bound to it, using the current values in its bound list.
What sort of exceptions are you getting after you call ResetBindings? Because it works just fine for me, whether I add, edit, delete, or remove rows from the underlying DataTable.
I ran into a similar problem. Here's a solution that is even simpler (if less elegant).
I found that this:
dataGridView.DataSource = null;
dataTable.BeginLoadData();
foreach(DataRow row in dataTable.Rows){
//modify row
}
dataTable.EndLoadData();
dataGridView.DataSource = dataTable;
...is way faster than this:
dataTable.BeginLoadData();
foreach(DataRow row in dataTable.Rows){
//modify row
}
dataTable.EndLoadData();
Cheers--DC
Just posting this as a solution: Making some notations to the comments and posts already.
The Merge Table method mentioned by BFree is a very good method to use and I think is the right approach not too mention very simple and elegant.
Here are my notes why and the big one I am not sure if any one caught was the hits on the server for the query.
The op stated in his comments to BFree that he would need to copy the table to do what he needed to, of course which table that was I am not sure , because his code:
foreach (DataRow row in data.Rows)
Those rows come from his table called data where is the copy required on that - he already has it.
Then here is something that just smacks right out on EACH Iteration of that loop :
SlowLoadingData slow_stuff = slow_query_results[(int)row["id"]];
Is the OP really querying the database each iteration of those rows (Which if it is a large table are we talking 100,000 rows +).
Think of the load on the Server (his app too must generate this query request!), and also the amount of traffic it places on a network to do this!
IF it is the only app maybe it's ok, but even at that it is not what I would prefer to do if I wanted to be efficient.
If gathering the data from the database in one query seems to much - then perhaps a better method would be to page his data in and do the merge.
SlowLoadingData Page1_SlowLoadingData = slow_query_results[Page1] as DataTable;
data.Merge(Page1_SlowLoadingData);
SlowLoadingData Page2_SlowLoadingData = slow_query_results[Page2] as DataTable;
data.Merge(Page2_SlowLoadingData);
I found that using resetBindings seems to move the scrollbar and the user is left thinking what did i do? I found that using a bindingList as a datasource, with an object that uses INotifyPropertyChanged, and then when I edited the row, (bound to an object). the row wasnt being updated until a click or selection change on the form.
but calling dgv.Refresh() seemed to solve the problem, without the scroll change.
I find the solution by Ravi LVS on codeproject works well:
BindingSource bs = new BindingSource();
DataTable dt = new DataTable();
bs.DataSource = dt;
bs.SuspendBinding();
bs.RaiseListChangedEvents = false;
bs.Filter = "1=0";
dt.BeginLoadData();
//== some modification on data table
dt.EndLoadData();
bs.RaiseListChangedEvents = true;
bs.Filter = "";
Link to original page: http://www.codeproject.com/Tips/55730/Achieve-performance-while-updating-a-datatable-bou

Categories