I'm working with a school project where we are supposed to build a simple booking system that utilizes SQL database. Used language is C# and environment Visual Studio Community 2017. I'm trying to build a function where user selects a row from dataGridView1 and clicks 'Add new invoice button'. The booking_id is extracted from dataGridView1 and passed to Form2 where booking-related data is searched with booking_id. This data is then presented in dataGridView2 which lists all services included in the one user-specified booking.
Database contains three relevant tables; Booking, Service and BoughServices.
Booking contains column booking_id (INT)
Services contains columns service_id (INT), name (VARCHAR) and price (INT)
BoughtServices, contains columns Booking.booking_id (INT),
Service.service_id (INT) and amount (INT)
Code on Form1:
// Establish a class for data.
public static class DataToForm2
{
public static int booking_id;
}
// User clicks button 'Add new invoice'.
private void button_CreateInvoice_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
//Note: CurrentRow.Cells[0] contains booking_id.
DataToForm2.booking_id = Convert.ToInt32(dataGridView1.CurrentRow.Cells[0].Value);
f2.Show();
}
Code on Form2:
private void Form2_Load(object sender, EventArgs e)
{
using(SqlConnection connection = new SqlConnection(connectionString))
{
// Set SQL query string.
string query = "SELECT Service.name, Services.price, BoughtServices.amount " +
"FROM Service " +
"INNER JOIN Service.service_id ON BoughtServices.service_id " +
"INNER JOIN Bookings ON Bookings.booking_id = BoughtServices.booking_id " +
"WHERE " +
"Booking.booking_id = #booking_id";
SqlCommand command = new SqlCommand(query, connection);
// Set query parameters.
command.Parameters.Add("#booking_id", SqlDbType.Int).Value = Form1.DataToForm2.booking_id;
// Run SQL query
var dataAdapter = new SqlDataAdapter(query, connection);
DataSet ds = new DataSet();
dataAdapter.Fill(ds);
dataGridView1.ReadOnly = true;
dataGridView2.DataSource = ds.Tables[0];
}
}
However, this approach is non-functional and crashes with an error System.Data.SqlClient.SqlException: Must declare the scalar variable "#booking_id. I have spent an increasing number of hours to figure this out and find solution from tutorials but so far they all have failed. Interestigly, everything is working just fine when I add booking_id directly to SQL statement. In otherwords, WHERE Booking.booking_id = 2 works like a charm.
Could someone help me and propose how I should format my code so that I am able to perform desired actions? Thank you in advance!
Almost right. The only problem is the SqlDataAdapter that receives the sql string and not the command where you have defined the parameter. Just change
// Run SQL query
var dataAdapter = new SqlDataAdapter(command);
As you can see there is a SqlDataAdapter's constructor that receives a SqlCommand where you could define parameters and set the connection.
You're using the parameterized SQL query incorrectly. It functions more like string.Replace than an assignment. Try
command.Parameters.Add("#booking_id",
Form1.DataToForm2.booking_id);
Related
I have a data grid view that shows all rows of a particular database table on a Windows form. Above the grid, I have text fields with corresponding buttons that a user can use to narrow down the data grid view by various criteria, such as By Customer Number, By Order Number, etc... I haven't been able to figure out how to accomplish this.
I've tried many examples I've found online, the most recent resulting the code below.
OleDbConnection connection = SerialsDatabaseDB.GetConnection();
string selectStatement
= "Select * "
+ "FROM Orders "
+ "WHERE CustomerNumber = #CustomerNumber";
OleDbCommand selectCommand =
new OleDbCommand(selectStatement, connection);
selectCommand.Parameters.AddWithValue("#CustomerNumber", custNumber);
OleDbDataAdapter dataAdapter =
new OleDbDataAdapter(selectStatement, connection);
DataSet dataSet = new DataSet("OrdersByCustomer");
connection.Open();
dataAdapter.Fill(dataSet, "OrdersByCustomer");
connection.Close();
dataGridView1.DataSource = dataSet;
dataGridView1.DataMember = "OrdersByCustomer";
Currently, I'm getting a "No value given for one or more required parameters" on the dataAdapter.Fill(dataSet, "OrdersByCustomer"); line.
Try your code with this change
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(selectCommand);
OleDbDataAdapter has 4 constructors. One of them takes an instance of OleDbCommand. In your code you are creating it but you are not passing it into relevant constructor. The parameter you created and added to the selectCommand is just remaining unused. The exception you are getting is the result of this.
So, I.ve actually googled a lot about that error, but some of the code that had a solution I couldn't understand, mainly because I'm new at c#, so I'll just put the problem as it is.
My professors called it "complex winform". That's basically data from 2 different tables that are linked with an inner join. So far so good.
I work with postgresql btw.
I have 2 main tables. Student (with idstudent, registrationid, yearofstudy) and Persons( with idperson, Name, Telephone, Email, etc). (idstudent = idperson)
There are around 20 PERSONS in my database and 7 STUDENTS. Students are also persons (duuh), ergo idstudent=idperson.
So, I have a combobox where i put a disctinct yearofstudy of all my students and it looks like this.
private void frmComplex1_Load(object sender, EventArgs e)
{
OdbcConnection conexiune;
conexiune = new OdbcConnection();
conexiune.ConnectionString = "Driver={PostgreSQL ANSI};database=postgres;server=localhost;port=5432;uid=postgres;sslmode=disable;readonly=0;protocol=7.4;fakeoidindex=0;showoidcolumn=0;rowversioning=0;showsystemtables=0;fetch=100;unknownsizes=0;maxvarcharsize=255;maxlongvarcharsize=8190;debug=0;commlog=0;usedeclarefetch=0;textaslongvarchar=1;unknownsaslongvarchar=0;boolsaschar=1;parse=0;extrasystableprefixes=dd_;lfconversion=1;updatablecursors=1;trueisminus1=0;bi=0;byteaaslongvarbinary=0;useserversideprepare=1;lowercaseidentifier=0;gssauthusegss=0;xaopt=1;pwd=irimia96";
conexiune.Open();
OdbcCommand comanda;
comanda = new OdbcCommand();
comanda.CommandText = "SELECT DISTINCT anstudiu from studenti ORDER BY anstudiu asc ";
comanda.Connection = conexiune;
OdbcDataReader cititor;
cititor = comanda.ExecuteReader();
DataSet dsDate;
dsDate = new DataSet();
DataTable tblStudenti;
tblStudenti = new DataTable("studenti");
tblStudenti.Load(cititor);
dsDate.Tables.Add(tblStudenti);
this.cboComplex1.DataSource = dsDate.Tables["studenti"];
this.cboComplex1.DisplayMember = "anstudiu";
this.cboComplex1.ValueMember = "anstudiu";
conexiune.Close();
}
So what im trying to do is, whenever I select a year (1/2/3) from that combobox, to get in return, in my first DataGrindView Information about students that are year 1/2/3 from BOTH STUDENT table and PERSON TABLE. For example: the students from yearofstudy 2 with. IdPerson, Name, Telephone, Email, RegistrationId, Student Id. (I know Student Id and Person Id will get the same value, but I dont care, first let it work)
So i type the script, and get this the datarawview error
private void cboComplex1_SelectedIndexChanged(object sender, EventArgs e)
{
OdbcConnection conexiune;
OdbcCommand comanda;
DataSet dsDate;
OdbcDataReader cititor;
DataTable tblPersoane;
conexiune = new OdbcConnection();
conexiune.ConnectionString = " Driver={PostgreSQL ANSI};database=postgres;server=localhost;port=5432;uid=postgres;sslmode=disable;readonly=0;protocol=7.4;fakeoidindex=0;showoidcolumn=0;rowversioning=0;showsystemtables=0;fetch=100;unknownsizes=0;maxvarcharsize=255;maxlongvarcharsize=8190;debug=0;commlog=0;usedeclarefetch=0;textaslongvarchar=1;unknownsaslongvarchar=0;boolsaschar=1;parse=0;extrasystableprefixes=dd_;lfconversion=1;updatablecursors=1;trueisminus1=0;bi=0;byteaaslongvarbinary=0;useserversideprepare=1;lowercaseidentifier=0;gssauthusegss=0;xaopt=1;pwd=irimia96";
conexiune.Open();
comanda = new OdbcCommand();
comanda.CommandText = "SELECT * from persoane INNER JOIN studenti on persoane.idpersoana = studenti.idstudent WHERE anstudiu =?";
comanda.Connection = conexiune;
comanda.Parameters.Clear();
comanda.Parameters.AddWithValue("anstudiu", cboComplex1.SelectedValue.ToString());
cititor = comanda.ExecuteReader();
tblPersoane = new DataTable("persoane");
tblPersoane.Load(cititor);
dsDate = new DataSet();
dsDate.Tables.Add(tblPersoane);
dGComplex.DataSource = dsDate;
dGComplex.DataMember = "persoane";
dGComplex.Refresh();
}
Srry for the long post, i'll give you a potato at the end.
Just invert the order of the settings for DisplayMember/ValueMember in relation to the setting of the DataSource property
this.cboComplex1.DisplayMember = "anstudiu";
this.cboComplex1.ValueMember = "anstudiu";
// Move this line after setting the Disply/ValueMember property
this.cboComplex1.DataSource = dsDate.Tables["studenti"];
This should ensure the proper binding of the strings used for Display/ValueMember against the field names of the datatable.
I should add that this mode doesn't catch an error if you mistype one of your field names (for example "anstdiu" will be accepted).
On the contrary, if you set the DataSource before the Display/ValueMember, trying to write an invalid name will get you a runtime exception.
I'm trying to filter-search the data from a GridView control which is bound to a SQL data connection but i'm not having any success. Whenever I try to search for something, it results in no records found. Here is my main searching code:
public void FilterGridView(string column, string terms) //SELECT * FROM [Table_1] WHERE [First Name] LIKE '%valuetosearchfor%' is the format to use here
{
DataTable filterTable = new DataTable(); //create a datatable to hold the data while we retrieve it
SqlConnection connection = new SqlConnection("Data Source=TAMUWINPART\\SQLEXPRESS;Initial Catalog=phpMyWorkers;Integrated Security=True"); //connect to SQL
try
{
connection.Open(); //open the connection
string filterStatement = "SELECT * FROM [Table_1] WHERE #column LIKE '%#terms%'"; //select all from table_1 with the correct column name / terms
SqlCommand sqlCmd = new SqlCommand(filterStatement, connection); //make a sql command
sqlCmd.CommandType = CommandType.Text; //make it an average joe sql text command
//define the # sql variables
sqlCmd.Parameters.AddWithValue("#column", column);
sqlCmd.Parameters.AddWithValue("#terms", terms);
SqlDataAdapter filterAdapter = new SqlDataAdapter(sqlCmd); //make a data adapter to get all the data from the command and put it into the data table
filterAdapter.Fill(filterTable); //fill the data table with the data from the SQL connection
if(filterTable.Rows.Count > 0) //if records were found relating to the terms
{
//if records WERE found
workersView.DataSource = filterTable; //set the data source to this instead
workersView.DataBind(); //refresh the data
}
else
{
//no records were found in this case, do not be an inneficient guy who will refresh the gridview for no reason
FilterSearchTerms.Text = "0 Records Found!"; //notify the user that he/she won't get anything
}
}
catch (System.Data.SqlClient.SqlException ex) //if the thing just decides that it doesn't want to work today
{
string msg = "myWorkers had a problem fetching the data : ";
msg += ex.Message;
throw new Exception(msg);
}
finally
{
connection.Close(); //close the connection
}
}
public void FilterSearchButton_Click(object sender, EventArgs e) //when someone clicks the button to filtersearch the gridviews
{
string column = FilterSearchDropdown.SelectedValue.ToString(); //get the column that the user wants to filter by and make sure it's a string
string terms = FilterSearchTerms.Text; //get the terms to search by - verified string for sure
FilterGridView(column, terms);
}
public void FilterRemoveButton_Click(object sender, EventArgs e) //when someone decides to remove the filter
{
BindGridView(); //refresh the gridview based on all of the data
FilterSearchTerms.Text = ""; //remove the text from the filter search terms box
}
Here is a picture of what the layout looks like.
Even if I search for real data it results in this being called
else
{
//no records were found in this case, do not be an inneficient guy who will refresh the gridview for no reason
FilterSearchTerms.Text = "0 Records Found!"; //notify the user that he/she won't get anything
}
meaning that the datatable's row count is 0...
Does anyone know why? Thank you.
I suspect that your SQL LIKE code is incorrect. Take a look at how to use like with SQL parameter in this question:how-to-get-like-clause-to-work-in-ado-net-and-sql-server. It would also help to display the final sql command text that gets sent to the database.
Replace this line :
string column = FilterSearchDropdown.SelectedValue.ToString();
with this:
string column = FilterSearchDropdown.SelectedText;
Also, you need correct your command string and command parameters as Emmad Kareem suggested in other answer. Your string and parameter should be like below:
string filterStatement = "SELECT * FROM [Table_1] WHERE [{0}] LIKE #terms"; //select all from table_1 with the correct column name / terms
filterStatement = string.Format(filterStatement, column);
.... .... .... .... .... ....
// sqlCmd.Parameters.AddWithValue("#column", column );
sqlCmd.Parameters.AddWithValue("#terms", "%" + terms + "%");
You only need to replace this query:
string filterStatement = "SELECT * FROM [Table_1] WHERE #column LIKE '%"+terms+"%'";
And you should be able to find your data.
I want to be able to execute a custom SQL query against a table adapter that I have. Is it possible to do this? Or can I only use the predefined queries on each table adapter in the dataset design view?
If I can't do this, how would I go about executing my SQL query against a table, and having the results display in my datagridview that's bound to a table adapter?
Thanks.
EDIT: I didn't explain myself properly. I know how to Add queries to a tableadapter using the dataset designer. My issue is i need to execute a custom peice of SQL (which i build dynamically) against an existing table adapter.
I posted a comment pointing to an example using VB which creates a class that extends TableAdapter. Instead of using the VB example and rewriting it in C# I will show how this can be done without creating a class that extends TableAdapter.
Basically create a BackgroundWorker to perform the sql query. You don't have to but it would be nice. Build the query string based on input from the user.
private void queryBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//Initialize sqlconnection
SqlConnection myConnection;
//Convert date in to proper int format to match db
int fromDate = int.Parse(dateTimePickerStartDate.Value.ToString("yyyyMMdd"));
int toDate = int.Parse(dateTimePickerEndDate.Value.ToString("yyyyMMdd"));
//Setup Parameters
SqlParameter paramFromDate;
SqlParameter paramToDate;
SqlParameter paramItemNo;
SqlParameter paramCustomerNo;
//Fill the data using criteria, and throw any errors
try
{
myConnection = new SqlConnection(connectionString);
myConnection.Open();
using (myConnection)
{
using (SqlCommand myCommand = new SqlCommand())
{
//universal where clause stuff
string whereclause = "WHERE ";
//Add date portion
paramFromDate = new SqlParameter();
paramFromDate.ParameterName = "#FromDate";
paramFromDate.Value = fromDate;
paramToDate = new SqlParameter();
paramToDate.ParameterName = "#ToDate";
paramToDate.Value = toDate;
myCommand.Parameters.Add(paramFromDate);
myCommand.Parameters.Add(paramToDate);
whereclause += "(TableName.date BETWEEN #FromDate AND #ToDate)";
//Add item num portion
if (!string.IsNullOrEmpty(itemNo))
{
paramItemNo = new SqlParameter();
paramItemNo.ParameterName = "#ItemNo";
paramItemNo.Value = itemNo;
myCommand.Parameters.Add(paramItemNo);
whereclause += " AND (Tablename.item_no = #ItemNo)";
}
//Add customer number portion
if (!string.IsNullOrEmpty(customerNo))
{
paramCustomerNo = new SqlParameter();
paramCustomerNo.ParameterName = "#CustomerNo";
paramCustomerNo.Value = customerNo;
myCommand.Parameters.Add(paramCustomerNo);
whereclause = whereclause + " AND (Tablename.cus_no = #CustomerNo)";
}
string sqlquery = "SELECT * FROM TableName ";
sqlquery += whereclause;
//MessageBox.Show(sqlquery);
myCommand.CommandText = sqlquery;
myCommand.CommandType = CommandType.Text;
myCommand.Connection = myConnection;
this.exampleTableAdapter.ClearBeforeFill = true;
this.exampleTableAdapter.Adapter.SelectCommand = myCommand;
this.exampleTableAdapter.Adapter.Fill(this.ExampleDataSet.ExampleTable);
}
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
I personally like the idea of coding a class that extends TableAdapter but this was a quick easy way of answering the OP's question. Sorry it took a year :)
Taken from here
To add a query to a TableAdapter in the Dataset Designer
Open a dataset in the Dataset Designer. For more information, see How to: Open a Dataset in the Dataset Designer.
Right-click the desired TableAdapter, and select Add Query.
-or-
Drag a Query from the DataSet tab of the Toolbox onto a table on the designer.
The TableAdapter Query Configuration Wizard opens.
Complete the wizard; the query is added to the TableAdapter.
I'm trying to learn some C#.net. I'm just trying to expose the AdventureWorks database included in my C# class via a web interface. Here's the setup:
I've got a DropDownList in on my ASPX page with an id of tableNameDropDown. It gets populated on Page_Load like this:
protected void Page_Load(object sender, EventArgs e)
{
conn.Open();
String table_names_sql = "select Name from sysobjects where type='u' ORDER BY name";
SqlCommand cmd = new SqlCommand(table_names_sql, conn);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
tableNameDropDown.Items.Add(reader[0].ToString());
}
conn.Close();
tableNameDropDown.AutoPostBack = true;
}
And that works just fine, I get a nice long list of the tables in the DB. When someone selects a table from the list, I want to display that table in a GridView control with an id of grid. This is what I've got:
protected void tableNameDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
DataSet dataSet = new DataSet();
String tableName = columnNameDropDown.SelectedItem.ToString();
String table_sql = String.Format("SELECT * FROM {0};", tableName);
SqlDataAdapter adapter = new SqlDataAdapter(table_sql, conn);
adapter.Fill(dataSet, tableName);
grid.DataSource = dataSet;
grid.DataMember = tableName;
}
When I debug the page, I get an error on the adapter.Fill(dataSet, tableName); line: SqlException: Inlvalid object name '{tableName}'.
The tables in the DB are the following:
dbo.AWBuildVersion
.... more dbo. tables
HumanResources.Department
HumanResources.Employee
.... more HumanResources tables
Person.Address
Person.AddressType
.... more Person tables
... Other prefixes are "Pdoduction, Purchasing, Sales"
There are probably ~50+ tables, and I get all their names (without the prefixes) into my DropDownList no problem, but I can't seem to query them.
Any ideas?
You've already answered yourself: you need to use also the prefix in the select statement you're executing, like
Select * From Person.Address
Beside that you should not use the sysobject tables, from SQL Server 2005 you have system views that helps you, so you can write a better statement to select tables:
select * From INFORMATION_SCHEMA.TABLES
Check also this article.
Regards
Massimo