private void btn_view_Click(object sender, EventArgs e)
{
con.Open();
OleDbDataAdapter da = new OleDbDataAdapter("Select * from tbl_emp", con);
DataSet ds = new DataSet();
da.Fill(ds);
dgv_emptable.DataSource = ds.Tables[0];
con.Close();
}
private void btn_insert_Click(object sender, EventArgs e)
{
con.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = "Insert into tbl_emp(emp_id,emp_name,emp_surname,designation_id,dept_id) Values(" + txt_id.Text + " , '" + txt_name.Text + "','" + txt_phone.Text + "'," + cmb_desigid.SelectedValue + ",'" + cmb_deptid.SelectedValue.ToString() +"')";
cmd.Connection = con;
cmd.ExecuteNonQuery();
MessageBox.Show("Record inserted");
con.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
con.Open();
OleDbDataAdapter da = new OleDbDataAdapter("Select * from tbl_designation", con);
DataSet ds = new DataSet();
da.Fill(ds);
cmb_desigid.DataSource = ds.Tables[0];
cmb_desigid.DisplayMember = "designation_type";
cmb_desigid.ValueMember = "designation_id";
con.Close();
con.Open();
OleDbDataAdapter db = new OleDbDataAdapter("Select * from tbl_dept",con);
DataSet dm = new DataSet();
db.Fill(dm);
cmb_deptid.DataSource = dm.Tables[0];
cmb_deptid.DisplayMember = "dept_name";
cmb_deptid.ValueMember = "dept_id";
con.Close();
}
I have bound my database and I am writing an insert query to insert data in table but I get the same error at cmd.ExecuteNonQuery
no given parameters are given for required parameters.
I have checked thoroughly but can't seem to find the error
I have used textbox for emp_id,emmp_name,emp_surname,and two combo boxes for designation_id and dept_id.
the dept_id and designation_id are foreign key in tbl_emp. and i also have used the combo box property.So can anyone please tell what the error is and also if i have writtern the combo box code properly...
You need to get in the habit of using "parameterized queries" - those won't just protect your code from the #1 vulnerability out there - SQL injection - they'll also solve a lot of thorny issues with adding quotes etc. to string values.
Try this code:
private void btn_insert_Click(object sender, EventArgs e)
{
// define the insert query - OleDB uses unnamed, positional parameters
string insertQuery = "INSERT INTO tbl_emp (emp_id, emp_name, emp_surname, designation_id, dept_id) " +
"VALUES (?, ?, ?, ?, ?)";
// create command
OleDbCommand cmd = new OleDbCommand(insertQuery, con);
// define parameters - in the proper order! - and set their values
// The "names" like "#emp_id" that I'm using here are just to make it easier for you to grasp which parameter
// corresponds to which columns being inserted - you could also name them "p1", "p2" etc. - not very intuitive, though ...
// Check the *assumptions* I made for the datatypes - not sure if those are
// really what you have - adapt as needed
cmd.Parameters.Add("#emp_id", OleDbType.Int).Value = Convert.ToInt32(txt_id.Text);
cmd.Parameters.Add("#emp_name", OleDbType.VarChar, 100).Value = txt_name.Text;
cmd.Parameters.Add("#emp_surname", OleDbType.VarChar, 100).Value = txt_phone.Text
cmd.Parameters.Add("#designation_id", OleDbType.Int).Value = cmb_desigid.SelectedValue;
cmd.Parameters.Add("#dept_id", OleDbType.Int).Value = cmb_deptid.SelectedValue;
// open connection, execute query, close connection
con.Open();
cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show("Record inserted");
}
As a general side note: if you're only ever interested in a single DataTable being returned from a query - I'd strongly recommend using this code (instead of what you have now):
private void Form1_Load(object sender, EventArgs e)
{
con.Open();
OleDbDataAdapter da = new OleDbDataAdapter("Select * from tbl_designation", con);
// define and use a "DataTable" - not a "DataSet" (which is overkill for just a single table of data)
DataTable dt = new DataTable();
da.Fill(dt);
cmb_desigid.DataSource = dt;
cmb_desigid.DisplayMember = "designation_type";
cmb_desigid.ValueMember = "designation_id";
con.Close();
I mentioned in the comments that you can get VS to do all this for you, in less time, and more securely/reliably than a human could do in a day. Writing db access code is boring and annoying, here's how you hand it off:
add a new dataset to the project, just like you would add a form or class or any other thing. Call it something sensible, not dataset1
open the server explorer window, and add a connection to your access db
drag the db into the dataset. Thoroughly read the long message box that pops up. No one reads this, and they should read it. It solves a lot of confusion later on when the build process is overwriting the database the exe is saving in, and it looks like your app never saves any data. Click yes
drag some tables out of the server explorer and into the dataset. Not the appearance of a datatabke with all the same columns as your db table and a tableadapter. This thing is NOT your database table, it is a strongly typed client side datatable which is a better version of what you're doing in your code above with weakly typed datasets and datatables. A tableadapter is a better version of a dataadapter designed to work with the better datatable it is visually attached to
switch to the forms designed
open the data sources window from the view menu, other windows submenu
drag one of the nodes out of data sources and onto the form
Many things appear, a data grid view, binding source, navigator, dataset, tableadapter, manager. Don't delete stuff until you understand how it all works because it will teach you a lot. Run the program
This app will work, load data, save data and you didn't so far write any code at all. VS wrote all the code for you and you can read it if you want, it's there in the .Designer.cs files on disk
Run the app, add some rows, change stuff, click save, close the app. Don't run the app again yet, but instead go into the bin/debug folder and open that db on there, in access. See your data you added/changed
Now close access and build the project again, now open the same bin/debug db in access.. see the data has gone? The build process copied the blank db from the project over the top of the db the exe altered when it ran. Make sure you grok what is happening here every time you build or you'll be very confused as to why your app "isn't saving" (it is, but the changes are being wiped by the build process)
Some other things you need to know about tableadapters:
they can have more than one select command- just right click them in the dataset designer and add another query. Use parameters, like SELECT * FROM t WHERE id = #id and give the command a sensible name like FillById. The tableadapter will gain a method myTabkeAdapter.FillById(someDatatableHere, 1234) to fill that datatable with row ID 1234
they have an Update method that takes a datatable. This is NOT JUST for running update queries. Update scans the whole passed on datatable looking for rows that need to be inserted updated or deleted and executes the relevant sql. When you change a datatable row, the change is tracked by the RowState property. If the rowstate is Added, and insert will be run by the table adapter, to insert the row. If the rowstate is Modified, an Update will be run. If the rowstate is deleted, a delete will be run. Microsoft should have called Update something else, like Save, because it causes confusion often
I am not understanding why I am getting an error after reading documentation in regards to the .Fill(). Am I missing something that is causing this to return with an error?
protected void FillData()
{
using (SqlConnection connection = new SqlConnection(#"Data Source = (LocalDB)\MSSQLLocalDB;AttachDbFilename= C:\Users\home\Documents\C# Programs\shop\Database.mdf ;Integrated Security = True"))
{
connection.Open();
using (SqlDataAdapter dataAdapter = new SqlDataAdapter("select * from Employee", connection))
{
DataTable table = new DataTable();
table.Fill(table);
employeeDataGridView.DataSource = table;
}
}
}
The problem is in this line of code
table.Fill(table);
You can't use table, to fill your table. The correct syntax would be
dataAdapter.Fill(table)
You can't populate a DataTable in that way, you need to fill your DataAdapter, use a DataSet and then set the DataGridView to use this.
using (SqlDataAdapter dataAdapter = new SqlDataAdapter("select * from Employee", connection))
{
var ds = new DataSet();
dataAdapter.Fill(ds);
employeeDataGridView.DataSource = ds.Tables[0];
}
The neatest way to code this up is:
protected void FillData()
{
using (SqlDataAdapter dataAdapter = new SqlDataAdapter("select * from Employee", #"Data Source = (LocalDB)\MSSQLLocalDB;AttachDbFilename= C:\Users\home\Documents\C# Programs\shop\Database.mdf ;Integrated Security=True"))
{
DataTable table = new DataTable();
dataAdapter.Fill(table);
employeeDataGridView.DataSource = table;
}
}
It'll get neater if you put your connection string in a static "global" variable somewhere
Points of note:
use the dataadapter constructor that takes two strings - it will create the connection and the command for you
you don't need to open the connection for the adapter- it knows how to
this means you can have just one using
if your sql needs parameters put them inside the using as dataAdapter.SelectCommand.Paramaters.Add...
you could turn this into a method that accepts any sql string and parameter collection and returns you a datatable
consider putting a WHERE clause in your sql; users might not like to see a grid with 20,000 employees in because it makes it harder to edit a handful of employees
It would be better to add a DataSet to your project (right click project, add>>new item, choose dataset - it gives you something that looks like a db visual design surface you can add queries to, create datatables that become components that can be added to your forms/create databound controls automatically) and create strongly typed datatables and table adapters
An alternative better route than this would be to use Dapper and strongly typed POCOs
I am trying to populate a datagrid table and add an additional combobox in a Winforms application to allow the user to select from an exception list.
The datagrid is populated using a Stored Procedure on SQL server.
(NOTE: due to my ITs security I have to go through a single server using linked servers to where the data is to query the data so the stored procedure uses dynamic SQL)
The data pulls properly and the additional combobox appears however once I select an exception on 1 row and try to go to the next row, the first combobox's selection disappears.
An additional question, given the nature or how I query the data, how would I update the data on the original sql tables from datagrid? Another stored procedure?
FYI, I'm a SQL developer but I'm fairly new to C#
My code is below for the datagridview method. Thanks in advance.
public void displayDataGridView(string param)
{
SqlConnection con = new SqlConnection("Data Source = SQLServer1; initial catalog=GlbDBNames; integrated security=true ");
{
SqlCommand cmd;
cmd = new SqlCommand(param, con);
cmd.CommandTimeout = 60 * 20;
cmd.CommandType = CommandType.Text;
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
dg_batchsummary.DataSource = ds.Tables[0];
dg_batchsummary.Columns[0].Width = 200;
dg_batchsummary.AutoGenerateColumns = false;
dg_batchsummary.AllowUserToAddRows = false;
DataGridViewComboBoxColumn ExceptionList = new DataGridViewComboBoxColumn();
ExcptionList.HeaderText = "Exception List";
ExceptionList.Name = "Newexcept";
ExceptionList.Items.AddRange("Item1","Item2","Item3");
dg_batchsummary.Columns.Add(ExceptionList);
}
I am having trouble writing my datagrid changes to the database, i am trying to type in the changes on the grid and then when Button_Add_Car is pressed i execute this code and write changes to the database but nothing is being written to the database.
private void Button_Add_Car(object sender, RoutedEventArgs e)
{
SqlConnection cn = new SqlConnection();
DataSet dt = new DataSet();
SqlDataAdapter da;
SqlCommandBuilder cmdBuilder;
cn.ConnectionString = (String.Format("Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLFunctions.connectSQL.SQLSERVER_ID, SQLFunctions.connectSQL.SQLDatabaseName, SQLFunctions.connectSQL.SQLServerLoginName, SQLFunctions.connectSQL.SQLServerPassword));
cn.Open();
da = new SqlDataAdapter("SELECT * FROM Cars", cn);
cmdBuilder = new SqlCommandBuilder(da);
da.Fill(dt);
da.Update(dt);
cn.Close();
}
Am i on the right track using this method?
Am i using the correct SQL Query? I am confused between the SELECT/INSERT as i have found examples where people are using both to achieve what i want to do. Surely i should be using the INSERT statement.
I made my own custom SQL Command to manually insert into the database so it is in fact working:
SQLCmd("INSERT INTO Cars (Date, Time) VALUES(2014-10-10, '12:00:00')");
EDIT 1:
Thanks to marc_s i managed to achieve some sort of inserting but i believe i need to modify the value section to be inside an IF Statement which will check if it is a null or not and change value back to cr.Date and cr.Time as i am making use of a list. I am unsure of how to utilize the if statement in this way because it is currently entering blank rows, although its a step in the right direction:
CarRecord cr = new CarRecord();
carRecords.Add(cr);
SqlConnection con = new SqlConnection(String.Format(#"Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLFunctions.connectSQL.SQLSERVER_ID, SQLFunctions.connectSQL.SQLDatabaseName, SQLFunctions.connectSQL.SQLServerLoginName, SQLFunctions.connectSQL.SQLServerPassword));
con.Open();
SqlCommand comm = new SqlCommand("INSERT INTO Cars VALUES (#Date, #Time)", con);
SqlDataAdapter da = new SqlDataAdapter(comm);
da.SelectCommand.Parameters.Add(new SqlParameter("#Date", SqlDbType.NVarChar)).Value = DBNull.Value;
da.SelectCommand.Parameters.Add(new SqlParameter("#Time", SqlDbType.NVarChar)).Value = DBNull.Value;
da.SelectCommand.ExecuteNonQuery();
DataTable dt = new DataTable();
SqlCommandBuilder builder = new SqlCommandBuilder(da);
da.Update(dt);
con.Close();
lets take your first code example.
take a look at the last 3 lines, first thing you do is to copy data from the table Cars and store that into the DataSet named dt.
then immediately after you store this dataset back into the database, without actually doing any changes.
if dot net is smart enough it wont do anything, since you didn't change anything between the fill and the update call.
what you probably should be doing is get the dataset from the datagrid or similar and store that one instead.
or do as you have started on in your second example of when you identity that a row is updated take the data from that row and construct an insert (or update) query to the database.
Found a bunch of other threads about comboboxes in WPF datagrid, but none that helped.
I have a connection to a MySQL database, and can populate a datagrid with the rows from a table. XAML:
<DataGrid Name="dataGridxxx" ItemsSource="{Binding}" AutoGenerateColumns="True" Height="279" AutoGeneratingColumn="dataGridxxx_AutoGeneratingColumn">
C#:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string MyConString =
"SERVER=xxx;" +
"DATABASE=xxx;" +
"UID=xxx;" +
"PASSWORD=xxx;";
string sql = "SELECT * FROM xxx ORDER BY lastName";
using (MySqlConnection connection = new MySqlConnection(MyConString))
{
connection.Open();
using (MySqlCommand cmdSel = new MySqlCommand(sql, connection))
{
DataTable dt = new DataTable();
MySqlDataAdapter da = new MySqlDataAdapter(cmdSel);
da.Fill(dt);
dataGridPatients.DataContext = dt;
}
connection.Close();
}
}
Now I have a "Province" field in the table, and it was made an enum('ON', 'MB', 'SK', etc.) in MySQL workbench. When I create the data connection in VS, I can see that VS sees it's an enum type. I thought if the AutoGenerateColumns was set to true, the grid is smart enough to put a combobox with the DB enum values in those Province table cells? That's not happening. It's just a plain old text field, with maxchars of 2...
Any ideas? Do I have to create a new DataSet in my project to create C# classes from my database schema?
The correct answer is in H.B.'s referenced post... "don't use them". Seeing as I'm new to databases as well, I didn't know the proper and standard way of handling enums is by using a reference table. Snagged the link from a few clicks away: Why MySQL enums are evil