Background: I have a Windows Forms Application with a DataGridView control that is bound to a DataSet. The DataSet is filled with data from a database view. Some of the DataGridView cells are editable, and rows need to be delete-able.
Problem: When a value in the grid is edited, how do I update the database? It does not appear to be nearly as easy as it would be if it were pointing to a database table, rather than a view. Should I be adding the tables relevant to the view to the DataSet as well, and then making the appropriate changes to the tables and then calling the update DataSet method?
Edit1: I think DataSets that point to a view with joins cannot have the Update() method called.
Edit2: With the below code, I get an error saying:
there is no definition for Update
when my DataSet looks at a view. However, if a DataSet points to a table, Update does exist. Both DataSet are autogenerated by VS. What am I doing wrong?
try
{
this.ASSIGNMENTS_VWTableAdapter.Update(this.TEST_Dataset.ASSIGNMENTS_VW);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Edit3: The following code is what I used to try the SqlCommandBuilder. I get the error I mentioned in my comment below "Dynamic SQL generation is not supported against multiple base tables."
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand("SELECT * FROM ASSIGNMENTS_VW", connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
connection.Open();
builder.GetUpdateCommand();
adapter.Update(tEST_ASSIGNMENTS_VW, "ASSIGNMENTS_VW");
}
Related
I am new to visual studio-2010. I am trying to create an application which reads data from sql database and shows on datagrid. I implemented the code which I found on internet.
here is the sql_button_Click function
private void sql_button_Click(object sender, RoutedEventArgs e)
{
string ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFilename='C:\\Users\\jakkulv\\Downloads\\VS projects\\employee\\employee\\SampleDatabase.mdf';Integrated Security=True;Connect Timeout=30;User Instance=True";
string SQL = "select emp_id,first_name from employee";
SqlConnection conn = new SqlConnection(ConnectionString);
// open the connection
conn.Open();
//Create a SqlDataAdapter object
SqlDataAdapter adapter = new SqlDataAdapter(SQL, conn);
// Call DataAdapter's Fill method to fill data from the
// Data Adapter to the DataSet
DataSet ds = new DataSet("employee"); //database table name is "employee"
ds.Clear();
adapter.Fill(ds);
// Bind data set to a DataGrid control
dataGrid1.ItemsSource = ds.DefaultViewManager;
if (ds.HasChanges(DataRowState.Added))
{
// New rows have been added to the dataset, add appropriate code.
MessageBox.Show("data set has changes");
}
else
{
MessageBox.Show("data set has no changes");
// No new rows have been added to the dataset, add appropriate code.
}
but when I execute the same it is showing the message box saying - "data set has no changes".
why dataset is not updated??How to update it??
Your code will always result in the message box with data set has no changes, since it doesn't have any changes.
The data is the same as when it comes from the database, and since you haven't modified it, removed any records or added any records, there are no changes.
Just as the MSDN docs say
Gets a value indicating whether the DataSet has changes, including new, deleted, or modified rows.
Try to modify it, and then call ds.HasChanges() and you'll see that it will return true.
Hy everyone i'd like to ask for help about loading datas into data grid view from mysql database and i get some errors! Here's my code for the load method
if(this.OpenConnection()==true)
{
mySqlDataAdapter = new MySqlDataAdapter("select * from adatok_omlesztett", connection);
DataSet DS = new DataSet();
mySqlDataAdapter.Fill(DS);
dataGridView1.DataSource = DS.Tables[0];
this.CloseConnection();
}
and after that i got an error : "key not foundexception was unhandled"
From the database structure: its only on tabe wich contains 70 colums an 100 rows . but if i try with less datas the grid view shows the datas without any error. i think the problem is somwhere in the data set using.
I wanted to update my dataset changes to my database, so I used this sort of code:
SqlCommandBuilder mySqlCommandBuilder = new SqlCommandBuilder(sqladap);
sqladap.Update(ds, TableName);
While it works properly I have used this code for another dataset in my project but the second one does not work. I traced this code and saw the rows of the dataset. It contains both last fetched rows and new rows but the SQLDataAdapter updates any data and also it does not throw an error.
here is the full code:
public static SqlDataAdapter AdapterStoredProcedure(string sp_Name, object obj)
{
ClsEventLogs EventLogs = new ClsEventLogs();
try
{
SqlConnection connection = SQLDBConnection();
SqlDataAdapter sqladap = new SqlDataAdapter(sp_Name, connection);
sqladap.SelectCommand.CommandType = CommandType.StoredProcedure;
if (obj != null)
{
Type t = obj.GetType();
string str = string.Empty;
System.Reflection.FieldInfo[] fields = t.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
sqladap.SelectCommand.Parameters.Add(new SqlParameter(field.Name, SqlDbType.VarChar, 200));
sqladap.SelectCommand.Parameters[field.Name].Value = field.GetValue(obj).ToString();
}
}
return sqladap;
}
catch(Exception er)
{
EventLogs.Eventlog("clsDataStore : ExecuteStoredProcedure", er.Message, ClsEventLogs.EventType.etCriticalError, false);
return null;
}
}
// Creating Adapter
SqlDataAdapter dAdap = null;
DataSet ds = new DataSet();
dAdap = clsDataStore.AdapterStoredProcedure("sp_SelectTbl_Client", null);
dAdap.Fill(ds, "tbl_client");
//here is where i'm Updating the dataset
SqlCommandBuilder mySqlCommandBuilder = new SqlCommandBuilder(sqladap);
sqladap.Update(ds, TableName);
You'll have to look (Debugger) at the generated SQL Update/Insert statements. Most likely they are flawed or even empty.
The CommandBuilder is extremely limited, it only deals with very simple SELECT a, b FROM table statements.
You will probably find that the SP that doesn't work contains a JOIN, computed column or something like that.
Best course: provide your own Update statements or SPs
To ask the dumb question: did you tell your adapter to commit the changes after calling the Update method?
EDIT: OK, now that you've posted your code, I have to ask another dumb question: what are you looking at to determine if the update worked? Are you connecting to a remote database right now, or a test database in the project? If it's the latter, then if you are rebuilding each time (something I'm in the habit of doing) then your working copy of the database (in the \bin directory) gets blown away and replaced with a fresh copy from wherever it's referenced from in the project. That assumes, of course, that you're using an embedded DB (like MSSQLCE).
Im having an issue with the next code:
try
{
OleDbConnection Conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database.accdb;Jet OLEDB:Database Password=LuzDary;");
OleDbDataAdapter Data = new OleDbDataAdapter("SELECT * FROM Articulos", Conn);
DataSet DSet = new DataSet();
Conn.Open();
Data.Fill(DSet);
Conn.Close();
_Articulos = DSet.Tables["Articulos"];
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
The try/catch is there because my VStudio 2010 installation isnt quite capable of detecting COM Exceptions somehow (Had the same issue creating the database with ADOX, the exception was uncaught, the code kept on running responsively somehow, but the DB was never written to the disk).
The DB already has the "Articulos" table, and i manually inserted some records there, but if i foreach the DataSet, i only get a Table named "Table". This is getting frustrating now :(
DSet.Tables[0].Rows is what you want.
This is what I mean.
_Articulos = DSet.Tables[0];
With that, _Articulos.Rows should be populated with the records in your database.
I know this is a basic function of the DataGridView, but for some reason, I just can't get it to work. I just want the DataGridView on my Windows form to submit any changes made to it to the database when the user clicks the "Save" button.
I populate the DataGridView according to a function triggered by a user selection in a DropDownList as follows:
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
SqlDataAdapter ruleTableDA = new SqlDataAdapter("SELECT rule.fldFluteType AS [Flute], rule.fldKnife AS [Knife], rule.fldScore AS [Score], rule.fldLowKnife AS [Low Knife], rule.fldMatrixScore AS [Matrix Score], rule.fldMatrix AS [Matrix] FROM dbo.tblRuleTypes rule WHERE rule.fldMachine_ID = '1003'", con);
DataSet ruleTableDS = new DataSet();
ruleTableDA.Fill(ruleTableDS);
RuleTable.DataSource = ruleTableDS.Tables[0];
}
In my save function, I basically have the following (I've trimmed out some of the code around it to get to the point):
using (SqlDataAdapter ruleTableDA = new SqlDataAdapter("SELECT rule.fldFluteType AS [Flute], rule.fldKnife AS [Knife],
rule.fldScore AS [Score], rule.fldLowKnife AS [Low Knife],
rule.fldMatrixScore AS [Matrix Score], rule.fldMatrix AS [Matrix]
FROM dbo.tblRuleTypes rule WHERE rule.fldMachine_ID = '1003'", con))
{
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(ruleTableDA);
DataTable dt = new DataTable();
dt = RuleTable.DataSource as DataTable;
ruleTableDA.Fill(dt);
ruleTableDA.Update(dt);
}
Okay, so I edited the code to do the following: build the commands, create a DataTable based on the DataGridView (RuleTable), fill the DataAdapter with the DataTable, and update the database. Now ruleTableDA.Update(dt) is throwing the exception "Concurrency violation: the UpdateCommand affected 0 of the expected 1 records."
I believe there are a few problems here:
The sequence to keep in mind is that when you load up your grid, it is pointed to a datatable/set already.
When you type into the grid, the changes are temporarily persisted to the data table that is bound to the grid. Therefore, you do not want to be creating a data table every time you save, because the changes that were made to the existing data table are being ignored.
Second issue is that you probably don't need to create a binding source everytime, because just like the first point, if the grid is showing data, there is already a binding source that it is bound to.
Third problem is that the SQLCommandBuilder class has methods like GetInsertCommand, GetUpdateCommand, etc. that must be used to actually get the appropriate commands.
using (SqlDataAdapter ruleTableDA = new SqlDataAdapter("SELECT rule.fldFluteType AS [Flute], rule.fldKnife AS [Knife],
rule.fldScore AS [Score], rule.fldLowKnife AS [Low Knife],
rule.fldMatrixScore AS [Matrix Score], rule.fldMatrix AS [Matrix]
FROM dbo.tblRuleTypes rule WHERE rule.fldMachine_ID = '1003'", con))
{
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(ruleTableDA);
DataTable dt = new DataTable();
dt = RuleTable.DataSource as DataTable;
//ruleTableDA.Fill(dt);
ruleTableDA.Update(dt);
}
MSDN documentation states that the update/delete/insert commands are automatically set when you manually set the SelectCommand. It doesn't mention that it does the same when you construct one with a SqlDataAdapter. Try adding these lines after creating your SqlCommanduBuilder.
ruleTableDA.UpdateCommand = commandBuilder.GetUpdateCommand()
ruleTableDA.InsertCommand = commandBuilder.GetInsertCommand()
ruleTableDA.DeleteCommand = commandBuilder.GetDeleteCommand()
You may need this to get the Update Command
ruleTableDA.UpdateCommand = commandBuilder.GetUpdateCommand();