getting an error when trying to find value in database - c#

So I have a textbox and a button. I want to enter a value into the textbox and it will find the value that i entered in the row from the table called 'ticket'. I also then want to create a 'rebate slip' object in a table called 'Rebateslip'. This table has 2 fields - an id which is autoincremented and the ticketId which is the value I entered in the textbox (so basically I'm just passing the ticketId I just found into the 'RebateSlip' table). I put all the functions in a class called 'model' then I call them in the button event handler.
public bool rebateslip(int ticketID)
{
SqlCommand myCommand = new SqlCommand("SELECT ID FROM ticket WHERE ID = #ticketID", con);
SqlDataAdapter sqlDa = new SqlDataAdapter(myCommand);
myCommand.Parameters.AddWithValue("#ticketID", ticketID);
var reader = myCommand.ExecuteReader();
return reader.HasRows;
}
public void createRebateslip(int ticketId)
{
SqlCommand myCommand = new SqlCommand("INSERT INTO RebateSlip (ticketId) VALUES (#ticketId); SELECT SCOPE_IDENTITY();", con);
myCommand.Parameters.AddWithValue("#ticketId", ticketId);
string insertID = (myCommand.ExecuteScalar()).ToString();
rebateSlipList.Add(new RebateSlip(Int32.Parse(insertID), ticketId));
}
It works for one number but if I try enter another number into the textbox I get the error there is already an open DataReader associated with command which must be closed first.
Here's the code for the button. If the value is found in the table then a 'rebatelip' should be created but that is also not working.
private void buttonPrintRebateSlip_Click(object sender, EventArgs e)
{
int id;
if (!int.TryParse(textBoxRebateSlip.Text, out id))
{
return;
}
if (model.rebateslip(id))
{
MessageBox.Show("Found ticket");
//create rebate slip object
model.createRebateslip(id);
textBoxRebateSlip.Clear();
}
else
{
MessageBox.Show("Ticket not in database");
textBoxRebateSlip.Clear();
}
}

Excerpt from SqlDataReader.Close Method:
You must explicitly call the Close method when you are through using
the SqlDataReader to use the associated SqlConnection for any other
purpose.
You should use the using Statement.
public bool rebateslip(int ticketID)
{
using(SqlCommand myCommand = new SqlCommand("SELECT ID FROM ticket WHERE ID = #ticketID", con))
{
using(SqlDataAdapter sqlDa = new SqlDataAdapter(myCommand))
{
myCommand.Parameters.AddWithValue("#ticketID", ticketID);
using(var reader = myCommand.ExecuteReader())
{
return reader.HasRows;
}
}
}
}
Anyway, your sqlDa SqlDataAdapter makes no sense in the context. Probably you only need:
public bool rebateslip(int ticketID)
{
using(SqlCommand myCommand = new SqlCommand("SELECT ID FROM ticket WHERE ID = #ticketID", con))
{
myCommand.Parameters.AddWithValue("#ticketID", ticketID);
using(var reader = myCommand.ExecuteReader())
{
return reader.HasRows;
}
}
}

reader.close once you're done with it.
Also -- you should use a using or try...catch block

This way you never have a reader variable. Still the using paradigm is better.
public bool rebateslip(int ticketID)
{
SqlCommand myCommand = new SqlCommand("SELECT ID FROM ticket WHERE ID = #ticketID", con);
SqlDataAdapter sqlDa = new SqlDataAdapter(myCommand);
myCommand.Parameters.AddWithValue("#ticketID", ticketID);
return myCommand.ExecuteReader().HasRows;
}
public void createRebateslip(int ticketId)
{
SqlCommand myCommand = new SqlCommand("INSERT INTO RebateSlip (ticketId) VALUES (#ticketId); SELECT SCOPE_IDENTITY();", con);
myCommand.Parameters.AddWithValue("#ticketId", ticketId);
int insertID = (int)myCommand.ExecuteScalar();
rebateSlipList.Add(new RebateSlip(insertID, ticketId));
}
Also it seems you are storing ticketID's in the Insert table (from insertID) and insertID's in the Ticket table (from ticketID). Instead you should use a third table where you store only insertID's and ticketID's, allowing a multiple to multiple relationships while allowing them to be changed/deleted with a single action.

Related

Fill public strings with Database info from userlogin

I have created a class that gets the user details from DB to strings (username,userpassword,usernr,usersubco).
What i want to happen is that those strings fill with the info from the user I login with.
public class Details
{
public connectionUser constring = new connectionUser();
public string Technr;
public string Techpass;
public string Techname;
public string Techsubco;
public Details()
{
using (SqlConnection con = new SqlConnection(constring.source))
{
myInlogForm myI = new myInlogForm();
con.Open();
SqlCommand cmd = new SqlCommand("select * from techs where technr=#technr", con);
cmd.Parameters.Add(#"technr", SqlDbType.Int).Value = myI.technr;
cmd.ExecuteNonQuery();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Technr = reader[0].ToString();
Techpass = reader[1].ToString();
Techname = reader[2].ToString();
Techsubco = reader[3].ToString();
break;
}
con.Close();
}
MessageBox.Show(Techname + Technr + Techpass + Techsubco);
}
myI = usercontrol (inlogscreen)
myIn.technummer is a public string that get value on loginbutton from textbox.
when I push login I got the message box from this class above (empty) and following error :
UPDATED !!!
System.Data.SqlClient.SqlException: 'The parameterized query
'(#technr int)select * from techs where technr=#technr' expects the
parameter '#technr', which was not supplied.'
public event EventHandler<EventArgs> callMenu; // oproep door mainform
public event EventHandler<EventArgs> callDash; // oproep door mainform
public int technr;
private void loginBtn_Click(object sender, EventArgs e)
{
using (SqlConnection con = new SqlConnection(cUser.source.ToString()))
{
con.Open();
SqlCommand cmd = new SqlCommand("select technr,techcode from techs where technr=#technr and techcode=#techcode", con);
cmd.Parameters.Add(#"technr",SqlDbType.Int).Value = userTxb.Text;
cmd.Parameters.Add(#"techcode",SqlDbType.VarChar).Value = passTxb.Text;
cmd.ExecuteNonQuery();
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0 && callMenu != null && callDash != null) // checks login is juist
{
callMenu(this, new EventArgs());
callDash(this, new EventArgs());
technr = int.Parse(userTxb.Text);
}
else
{
MessageBox.Show("Foutieve gegevens");
}
con.Close();
}
}
try it in this way
cmd.Parameters.Add(#"#technr", SqlDbType.Int).Value = myI.technr;

How to get the data when I select a datagridview cell or column

I have 2 datagridview controls in a Windows Forms application.
I would like to get the info of a person when I select first datagridview cell or row to next datagridview:
try
{
ConnectionStringSettings consettings = ConfigurationManager.ConnectionStrings["attendancemanagement"];
string connectionString = consettings.ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
con.Open();
adap3 = new SqlDataAdapter(#"SELECT Date,Attendance,Remarks FROM dailyattendance where employee_id='"+DailyGV.CurrentRow+"'", con);
ds3 = new DataSet();
adap3.Fill(ds3, "dailyattendance");
dataGridView1.DataSource = ds3.Tables[0];
}
Im trying the above code. But it's not working.
I'm not too sure what DailyGV.CurrentRow is but basically you can use the RowHeaderMouseClick...see MSDN documentation. To use it, hook an event handler to it when initializing the form components (you can use VS designer as well...
dataGridView1.RowHeaderMouseClick += dataGridView1_RowHeaderMouseClick;
void dataGridView1_RowHeaderMouseClick(
object sender, DataGridViewCellMouseEventArgs e)
{
}
this event handler will get fired everytime you select a row header in the DataGridView control which will pass information about the event through an instance of the DataGridViewCellMouseEventArgs class (see MSDN documentation). This argument has a RowIndex property that provides the index of the row clicked which you can use to retrieve the values of the cells in that row...including the person id (if provided)...for example...
void dataGridView1_RowHeaderMouseClick(
object sender, DataGridViewCellMouseEventArgs e)
{
string personId = dataGridView1.Rows[e.RowIndex].Cells["PersonId"].Value;
//TODO: implement your own query to retrieve data for that person id
}
notice that you need to provide a proper column name when access the cells collection indexer...Cells["columnName"]
I will not give any description about the solution because Leo and Arsalan Bhatti has already suggested the solution. I am just telling you how your code should looks like and how it should be written.
string connectionString = consettings.ConnectionString;
using (SqlConnection con = new SqlConnection(connectionString))
{
try
{
con.Open();
string empID = DailyGV.CurrentRow.Cells["employee_id"].Value.ToString();
SqlCommand Cmd = con.CreateCommand();
Cmd.CommandText = "SELECT Date,Attendance,Remarks FROM dailyattendance where employee_id=#employee_id";
Cmd.Parameters.Add("#employee_id", SqlDbType.Int).Value = Int32.Parse(empID);
adap3 = new SqlDataAdapter(Cmd);
DataTable dt = new DataTable();
adap3.Fill(dt);
dataGridView1.DataSource = dt;
con.Close();
}
catch
{}
}
try
{
cn.Open();
string query = "select employee_id,Employee_Name,Image_of_Employee from Employee_Details where employee_id='" + dataGridView1.SelectedCells[0].Value.ToString() + "'";
SqlCommand cmd = new SqlCommand(query, cn);
SqlDataReader sdr;
sdr = cmd.ExecuteReader();
if (sdr.Read())
{
string aa = (string)sdr["employee_id"];
string bb = (string)sdr["employee_name"];
txtEmployeeID.Text = aa.ToString();
txtnameofemployee.Text = bb.ToString();
byte[] img=(byte[])sdr["Image_of_employee"];
MemoryStream ms=new MemoryStream(img);
ms.Seek(0,SeekOrigin.Begin);
pictureBox1.Image=Image.FromStream(ms); cn.Close();
}
}
catch (Exception e1)
{
MessageBox.Show(e1.Message);
}
You are passing the current row's index as employee id in SELECT query. Pass employee id for the selected record. Then it will work fine.

Using SQL datareader to extract 1 to many custom object in c#

I'm having issues with the SQL reader class.
I have a custom object named Airport on the database. But im having trouble using the datareader correctly. When i try to extract all Airports into a list(see method 2 below) it seems to jump of the while(_reader.Read()) loop before adding the object to the list.
Any suggestions?
To extract the object do i use 3 methods:
To find a specific object:
public Airport FindAirportByCode(string _airportCode)
{
con.Open();
string query = "SELECT * from Airport WHERE airportCode = '" + _airportCode + "'";
SqlCommand cmd = new SqlCommand(query, con);
SqlDataReader _reader = cmd.ExecuteReader();
Airport retAirport = BuildAirport(_reader);
_reader.Close();
con.Close();
return retAirport;
}
To get all Airports into a list
public List<Airport> SelectAll()
{
con.Open();
List<Airport> airports = new List<Airport>();
string query = "SELECT * from Airport";
SqlCommand cmd = new SqlCommand(query, con);
SqlDataReader _reader = cmd.ExecuteReader();
while (_reader.Read())
{
Airport temAirport = new Airport();
temAirport = BuildAirport(_reader);
airports.Add(temAirport); // It seems to skip this step and only add the last Airport from BuildAirport to the list.
}
_reader.Close();
con.Close();
return airports;
}
To build it into an object in C#
private Airport BuildAirport(SqlDataReader _reader)
{
Airport temAirport = new Airport();
while (_reader.Read())
{
temAirport.airportCode = (string) _reader["airportCode"];
temAirport.airportName = (string) _reader["airportName"];
temAirport.country = (string) _reader["country"];
temAirport.city = (string) _reader["city"];
}
_reader.Close();
return temAirport;
}
In third step you are enumarating reader again and that is why you get only one airport when you want to retrieve all of them.
private Airport BuildAirport(SqlDataReader _reader)
{
Airport temAirport = new Airport();
temAirport.airportCode = (string) _reader["airportCode"];
temAirport.airportName = (string) _reader["airportName"];
temAirport.country = (string) _reader["country"];
temAirport.city = (string) _reader["city"];
return temAirport;
}
And now we have to change your first method because changing BuildAirport breaks it. We have to read one row in FindAirportByCode now.
public Airport FindAirportByCode(string _airportCode)
{
con.Open();
string query = "SELECT * from Airport WHERE airportCode = #airportCode";
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("#airportCode", _airportCode);
SqlDataReader _reader = cmd.ExecuteReader();
Airport retAirport = null;
if (_reader.Read())
{
retAirport = BuildAirport(_reader);
}
_reader.Close();
con.Close();
return retAirport;
}
Use parametrized queries for security.

How to call a stored procedure using ADO.NET?

private void button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=*******;Initial Catalog=ChatApp;User ID=Chatapplication;Password=****";
conn.Open();
SqlCommand cmd = new SqlCommand();
string chatroomidno = textBox1.Text;
string chatroomname = textBox2.Text;
//cmd.CommandText = "Select ChatRoomID=#ChatRoomID,ChatRoomName=#ChatRoomName from tblChatRoom";
//cmd.Connection = conn;
SqlDataAdapter adapt = new SqlDataAdapter("Chatroomapp",conn);
adapt.SelectCommand.CommandType = CommandType.StoredProcedure;
DataSet ds=new DataSet();
DataTable dt = new DataTable();
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomID", SqlDbType.VarChar, 100));
adapt.SelectCommand.Parameters["#ChatRoomID"].Value = chatroomidno;
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomName", SqlDbType.VarChar, 50));
adapt.SelectCommand.Parameters["#ChatRoomName"].Value = chatroomname;
adapt.Fill(ds, "tblChatRoom");
if (dt.Rows.Count > 0)
{
MessageBox.Show("Connection Succedded");
}
else
{
MessageBox.Show("Connection Fails");
}
}
catch (Exception ex)
{
MessageBox.Show("Error", ex.Message);
}
}
While compiling the program I got only connection fails message box, in the database. I found correct, how to overcome the program to get the connection succeeded message box.
Well, you're filling the ds data set - but then you're checking the dt data table for presence of rows... that's never going to work, of course!
If you only need a single DataTable - just use and fill that data table alone - no need for the overhead of a DataSet. Also, put your SqlConnection and SqlCommand into using blocks like this:
using (SqlConnection conn = new SqlConnection("Data Source=*******;Initial Catalog=ChatApp;User ID=Chatapplication;Password=****"))
using (SqlCommand cmd = new SqlCommand("Chatroomapp", conn))
{
string chatroomidno = textBox1.Text;
string chatroomname = textBox2.Text;
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
adapt.SelectCommand.CommandType = CommandType.StoredProcedure;
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomID", SqlDbType.VarChar, 100));
adapt.SelectCommand.Parameters["#ChatRoomID"].Value = chatroomidno;
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomName", SqlDbType.VarChar, 50));
adapt.SelectCommand.Parameters["#ChatRoomName"].Value = chatroomname;
// fill the data table - no need to explicitly call `conn.Open()` -
// the SqlDataAdapter automatically does this (and closes the connection, too)
DataTable dt = new DataTable();
adapt.Fill(dt);
if (dt.Rows.Count > 0)
{
MessageBox.Show("Connection Succedded");
}
else
{
MessageBox.Show("Connection Fails");
}
}
And just because you get back no rows in dt.Rows doesn't necessarily mean that your connection failed..... it could just be that there are no rows that match your search critieria! The connection worked just fine - but the SQL command just didn't return any rows.
Connection failed means that something went wrong between your program and the database. No records returned does not mean that the connection failed. It just means that your table is empty - it contains no records.
Using ADO.NET and a stored procedures would have been a little different from what you have done it. If you need to check if the connection failed, maybe it is better to check the type of exception that is returned in the catch part.
Below is how I would have done it. I would have created a separate method that would have handled my call, and then in your button1_Click I would have just called this method:
public async Task<ChatRoom> GetAsync(string chatRoomId, string chatRoomName)
{
try
{
string connectionString = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
await sqlConnection.OpenAsync();
using (SqlCommand sqlCommand = new SqlCommand("ChatRooms_Get", sqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.Add(new SqlParameter("#ChatRoomID", chatRoomId));
sqlCommand.Parameters.Add(new SqlParameter("#ChatRoomName", chatRoomName));
using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync())
{
ChatRoom chatRoom = null;
if (await sqlDataReader.ReadAsync())
{
chatRoom = new ChatRoom();
chatRoom.Id = sqlDataReader.GetFieldValue<string>(0);
chatRoom.Name = sqlDataReader.GetFieldValue<string>(1);
chatRooms.Add(chatRoom);
}
return chatRoom;
}
}
}
}
catch (Exception exception)
{
// Try checking if the connection failed here
throw exception;
}
}
My chat room domain model could have looked like this:
public class ChatRoom
{
public string Id { get; set; }
public string Name { get; set; }
}
And the stored procedure would have looked like this:
CREATE PROCEDURE [dbo].[ChatRooms_Get]
(
#ChatRoomID VARCHAR(100),
#ChatRoomName VARCHAR(50)
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
ChatRoomID,
ChatRoomName
FROM
tblChatRoom
WHERE
ChatRoomID = #ChatRoomID
AND ChatRoomName = #ChatRoomName;
END
GO
And then in the calling method you would get the chatroom and do with it whatever you need to do with it. For this example I just checked if it exists or not:
try
{
ChatRoom chatRoom = await chatRoomRepository.GetAsync(chatRoomId, chatRoomName);
if (chatRoom != null)
{
MessageBox.Show("Record found");
}
else
{
MessageBox.Show("No record found");
}
}
catch (Exception exception)
{
throw exception;
}
I hope this can help.

How to create sql connection with c# code behind, access the sql server then conditionally redirect?

This is a question from an experienced beginner!
Using ASP.NET 4 C# AND SQL server,
I have a connection string in web.config to myDatabase named "myCS".
I have a database named myDB.
I have a table named myTable with a primary key named myPK
What are the NECESSARY lines of code behind (minimal code) to create a SQL connection, then select from myTable where myPK=="simpleText"
it will probably include:
sqlconnection conn = new sqlconnection(??? myCS)
string SQLcommand = select * from myDB.myTable where myPK==myTestString;
sqlCommand command = new SqlCommand(SQL,conn);
conn.Open();
booleanFlag = ????
conn.Close();
conn.Dispose();
then
If ( theAnswer != NULL ) // or (if flag)
{
Response.Redirect("Page1.aspx");
}
else
{
Response.Redirect("Page2.aspx");
}
Here is a limited simple tutorial:
First, you want to have a class to do the hard work for you, then you will use it with ease.
First, you have to crate the connection string in your web.config file and name it.
Here it is named DatabaseConnectionString, but you may named it myCS as required in the question.
Now, in App_Code create a new class file and name it SqlComm (this is just an example name) like:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
public class SqlComm
{
// this is a shortcut for your connection string
static string DatabaseConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["dbConStr"].ConnectionString;
// this is for just executing sql command with no value to return
public static void SqlExecute(string sql)
{
using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
}
// with this you will be able to return a value
public static object SqlReturn(string sql)
{
using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
object result = (object)cmd.ExecuteScalar();
return result;
}
}
// with this you can retrieve an entire table or part of it
public static DataTable SqlDataTable(string sql)
{
using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Connection.Open();
DataTable TempTable = new DataTable();
TempTable.Load(cmd.ExecuteReader());
return TempTable;
}
}
// sooner or later you will probably use stored procedures.
// you can use this in order to execute a stored procedure with 1 parameter
// it will work for returning a value or just executing with no returns
public static object SqlStoredProcedure1Param(string StoredProcedure, string PrmName1, object Param1)
{
using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
{
SqlCommand cmd = new SqlCommand(StoredProcedure, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter(PrmName1, Param1.ToString()));
cmd.Connection.Open();
object obj = new object();
obj = cmd.ExecuteScalar();
return obj;
}
}
}
Okay, this only a class, and now you should know how to use it:
If you wish to execute a command like delete, insert, update etc. use this:
SqlComm.SqlExecute("TRUNCATE TABLE Table1");
but if you need to retrieve a specific value from the database use this:
int myRequiredScalar = 0;
object obj = new object();
obj = SqlComm.SqlReturn("SELECT TOP 1 Col1 FROM Table1");
if (obj != null) myRequiredScalar = (int)obj;
You can retrieve a bunch of rows from the database this way (others like other ways)
This is relevant to your sepecific question
int Col1Value = 0;
DataTable dt = new DataTable();
dt = SqlComm.SqlDataTable("SELECT * FROM myTable WHERE myPK='simpleText'");
if (dt.Rows.Count == 0)
{
// do something if the query return no rows
// you may insert the relevant redirection you asked for
}
else
{
// Get the value of Col1 in the 3rd row (0 is the first row)
Col1Value = (int)dt.Rows[2]["Col1"];
// or just make the other redirection from your question
}
If you need to execute a stored procedure with or without returning a value back this is the way to do that (in this example there are no returning value)
SqlComm.SqlStoredProcedure1Param("TheStoredProcedureName", "TheParameterName", TheParameterValue);
Again, for your specific question return the table using the SqlDataTable , and redirect if dt.Rows.Count >0
Have fun.
There are many ways: LINQ, SqlDataReader, SQLDataAdapter, according to what you want to read (single value, datatable ...), so here is an example:
using (SqlConnection con = new SqlConnection("SomeConnectionString"))
{
var cmd = new SqlCommand("select from myTable where myPK==N'"+ simpleText+ "'",con);
cmd.Connection.Open();
var sqlReader = cmd.ExecuteReader();
while(sqlReader.Read())
{
//Fill some data like : string result = sqlReader("SomeFieldName");
}
sqlReader.Close();
cmd.Connection.Close();
cmd.Dispose();
}

Categories