SQL INSERT an ID of freshly inserted row - c#

im writing a library database program. It can insert books, but I have a problem in making a reference between book and a person which rents it. I can't get a last inserted id from a rents table to put it to the compilation table to assign book to a person who rents it. I've tried SCOPE_IDENTITY() but it doesn't works for me. Here's the code:
private void addRentButton_Click(object sender, EventArgs e) {
elibrary f1 = new elibrary();
string query = "INSERT INTO rents VALUES (#renterName, #rentStartDate, #rentEndDate)";
using(f1.Connection = new SqlConnection(f1.connectionString))
using(SqlCommand command = new SqlCommand(query, f1.Connection)) {
f1.Connection.Open();
command.Parameters.AddWithValue("#renterName", rentNameBox.Text);
command.Parameters.AddWithValue("#rentStartDate", DateTime.Now);
command.Parameters.AddWithValue("#rentEndDate", rentEndDatePicker.Value);
command.ExecuteScalar();
}
rentEndDatePicker.Value = DateTime.Now;
string Compilationquery =" INSERT INTO compilation VALUES (#bookId, SELECT SCOPE_IDENTITY())";
using(f1.Connection = new SqlConnection(f1.connectionString))
using(SqlCommand command = new SqlCommand(Compilationquery, f1.Connection)) {
f1.Connection.Open();
command.Parameters.AddWithValue("#bookId", f1.listBook.SelectedValue);
command.ExecuteScalar();

Actually, you are not retrieving the last inserted ID value from the first query, since the SCOPE_IDENTITY() is wrongly placed and you are not assigning the ExecuteScalar() return value anywhere:
String query = "INSERT INTO rents VALUES (#renterName, #rentStartDate, #rentEndDate); SELECT CONVERT(INT, SCOPE_IDENTITY())"; // "SELECT CAST(SCOPE_IDENTITY() AS INT)" can also be an option
Int32 lastId = 0;
using (f1.Connection = new SqlConnection(f1.connectionString))
using (SqlCommand command = new SqlCommand(query, f1.Connection))
{
f1.Connection.Open();
command.Parameters.AddWithValue("#renterName", rentNameBox.Text);
command.Parameters.AddWithValue("#rentStartDate", DateTime.Now);
command.Parameters.AddWithValue("#rentEndDate", rentEndDatePicker.Value);
lastId = (Int32)command.ExecuteScalar();
}
Once this is done, you can proceed with the second query as follows:
String compilationQuery = "INSERT INTO compilation VALUES (#bookId, #rentId)";
using (f1.Connection = new SqlConnection(f1.connectionString))
using (SqlCommand command = new SqlCommand(compilationQuery, f1.Connection))
{
f1.Connection.Open();
command.Parameters.AddWithValue("#bookId", f1.listBook.SelectedValue);
command.Parameters.AddWithValue("#rentId", lastId);
// ...

You have disposed the command so SCOPE_IDENTITY() is gone. There is no reason to dispose of the commmand twice.
using(SqlCommand command = new SqlCommand(query, f1.Connection))
{
f1.Connection.Open();
command.Parameters.AddWithValue("#renterName", rentNameBox.Text);
command.Parameters.AddWithValue("#rentStartDate", DateTime.Now);
command.Parameters.AddWithValue("#rentEndDate", rentEndDatePicker.Value);
command.ExecuteScalar();
int id = (Int32)command.ExecuteScalar();
command.Parameters.Clear();
Compilationquery = "INSERT INTO compilation VALUES (#bookId, #id)";
command.CommandText = Compilationquery;
command.Parameters.AddWithValue("#bookId", f1.listBook.SelectedValue);
command.Parameters.AddWithValue("#id", id);
command.ExecuteScalar();
}

Related

How to get selected ID from SQL database using textBox and update information?

I am trying to update a databse entry under a specific id in my table when the users enter their ID number in a textBox.
At the moment it updates but updates all entries in my table except the entry containing the users ID number.
This is the code I am currently using:
private void Button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(#"Data Source=DEVELOPMENT\ACCESSCONTROL;Initial Catalog=ACCESSCONTROL;User ID=sa;Password=P#55w0rd123");
SqlCommand check_User_Name = new SqlCommand("SELECT Id FROM NewVisitor WHERE (IDNumber = #IDNumber)", con);
check_User_Name.Parameters.AddWithValue("#IDNumber", idNumber_TxtBox.Text);
con.Open();
int UserExist = (int)check_User_Name.ExecuteScalar();
if (UserExist > 0)
{
var connetionString = #"Data Source=DEVELOPMENT\ACCESSCONTROL;Initial Catalog=ACCESSCONTROL;User ID=sa;Password=P#55w0rd123";
var sql = "UPDATE NewVisitor SET PersonVisit = #PersonVisit, PurposeVisit = #PurposeVisit, Duration = #Duration, Disclaimer = #Disclaimer";
try
{
using (var connection = new SqlConnection(connetionString))
{
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#PersonVisit", SqlDbType.NVarChar).Value = personVisiting_TxtBox.Text;
command.Parameters.Add("#PurposeVisit", SqlDbType.NVarChar).Value = purposeOfVisit_CMBox.SelectedItem;
command.Parameters.Add("#Duration", SqlDbType.Date).Value = duration_dateTimePicker1.Value.Date;
command.Parameters.Add("#Disclaimer", SqlDbType.NVarChar).Value = disclaimer_CHKBox.Checked;
connection.Open();
command.ExecuteNonQuery();
}
}
}
The whole table has many more fields but would like to just update the above fields within that specific ID.
Thanks
You forgot the WHERE clause on the UPDATE statement, telling it specifically which records to update. It sounds like you just want to add the exact same WHERE clause that you have on your SELECT:
var sql = "UPDATE NewVisitor SET PersonVisit = #PersonVisit, PurposeVisit = #PurposeVisit, Duration = #Duration, Disclaimer = #Disclaimer WHERE (IDNumber = #IDNumber)";
And don't forget to add the paramter for it:
command.Parameters.Add("#IDNumber", SqlDbType.Int).Value = idNumber_TxtBox.Text;
You may need to convert the input value to an integer first, I'm not 100% certain (it's been a while since I've had to use ADO.NET directly). Something like this:
if (!int.TryParse(idNumber_TxtBox.Text, out var idNumber))
{
// input wasn't an integer, handle the error
}
command.Parameters.Add("#IDNumber", SqlDbType.Int).Value = idNumber;

Returning the row id from stored procedure in C#?

I'm trying to get the row id of a row that is inserted.
This is the Fuel class:
public class Fuel
{
private Int32 fuelId;
private DateTime fuelDate;
public Fuel(DateTime fuelDate)
{
this.fuelDate = fuelDate;
}
public Fuel(Int32 fuelId, DateTime fuelDate)
{
this.fuelId = fuelId;
this.fuelDate = fuelDate;
}
public Int32 FuelId() { return fuelId; }
public DateTime FuelDate() { return fuelDate; }
}
This is the method that is trying to write to the database:
protected String connectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;
AttachDbFilename=" + "C:\\Users\\keith_000\\Documents\\Visual Studio 2017\\Projects\\RubberDress\\RubberDress\\Rubber.mdf" + ";" +
"Integrated Security=True;" +
"Connect Timeout=30";
public Int32 InsertFuelPurchase(Fuel myAddFuel)
{
Int32 myFuelId;
using (SqlConnection mySqlConn = new SqlConnection(connectionString))
{
mySqlConn.Open();
using (SqlCommand myComm = new SqlCommand("FUELINSERT", mySqlConn))
{
myComm.CommandType = CommandType.StoredProcedure;
myComm.Parameters.Add("#FUELDATE", SqlDbType.DateTime).Value = myAddFuel.FuelDate();
myComm.Parameters.Add("#FUELID", SqlDbType.Int).Direction = ParameterDirection.Output;
myFuelId = Convert.ToInt32(myComm.Parameters["#FUELID"].Value);
mySqlConn.Close();
}
}
return myFuelId;
}
The stored procedure is
CREATE PROCEDURE [dbo].[FUELINSERT]
#FUELDATE DATETIME,
#FUELID INT OUTPUT
AS
INSERT INTO FUELPURCHASE (FUELPURCHASEDATE)
VALUES (#FUELDATE)
SELECT #FUELID = SCOPE_IDENTITY()
Which is writing to the following table
CREATE TABLE [dbo].[FUELPURCHASE]
(
[FUELPURCHASEID] INT IDENTITY (1, 1) NOT NULL,
[FUELPURCHASEDATE] DATETIME NOT NULL
PRIMARY KEY CLUSTERED ([FUELPURCHASEID] ASC)
);
Currently the result which is being returned is 0.
When I debug the method I find it 0 is being returned from the stored procedure.
Can anyone spot where I have to resolve the problem?
Of course you need to execute the command, (ExecuteScalar, ExecuteNonQuery, even ExecuteReader will call the SP and runs your SqlCommand) but you don't need to have an out parameter, just SELECT SCOPE_IDENTITY() in the stored procedure and execute the command with ExecuteScalar
CREATE PROCEDURE [dbo].[FUELINSERT]
#FUELDATE DATETIME
AS
INSERT INTO FUELPURCHASE (FUELPURCHASEDATE) VALUES (#FUELDATE)
SELECT SCOPE_IDENTITY()
Now you can call the SP with
....
using (SqlCommand myComm = new SqlCommand("FUELINSERT", mySqlConn))
{
myComm.CommandType = CommandType.StoredProcedure;
myComm.Parameters.Add("#FUELDATE", SqlDbType.DateTime).Value = myAddFuel.FuelDate();
myFuelId = Convert.ToInt32(myComm.ExecuteScalar());
}
....
You are missing myComm.ExecuteNonQuery();...your code should looks like:
myComm.ExecuteNonQuery();
myFuelId = Convert.ToInt32(myComm.Parameters["#FUELID"].Value);
try this:
mySqlConn.Open();
using (SqlCommand myComm = mySqlConn.CreateCommand())
{
myComm.CommandType = CommandType.StoredProcedure;
myComm.CommandText = "Exec YourProcedure #FUELDATE,#FUELID";
myComm.Parameters.Add("#FUELDATE", SqlDbType.DateTime).Value = myAddFuel.FuelDate();
myComm.Parameters.Add("#FUELID", SqlDbType.Int).Direction = ParameterDirection.Output;
myFuelId = Convert.ToInt32(myComm.Parameters["#FUELID"].Value);
int result = myComm.ExecuteNonQuery();
mySqlConn.Close();
return result;
}
when returning a single value use myComm.ExecuteScalar()
It is depend on your FUELDATE, FUELID position:

ASP.NET Multiple Queries not executing within a loop

I am trying to run multiple queries within a loop. The first query runs ok as I can see it when I step through the code.
However the second query (which is within a loop) is supposed to run depending on the value held from the first. When the loop runs based on that value it seems to be ignoring the query. I put a label to display in place of the query and it displayed so I believe how I have opened/closed my connection is not correct.
c# code:
protected void Page_Load(object sender, EventArgs e)
{
// Get the session of the user
string staffid = Session["StaffId"].ToString();
//Proxy on page load to check IsActive Status
string DefaultConnection = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
SqlConnection myConnection = new SqlConnection(DefaultConnection);
myConnection.Open();
//select the userdetail specific to the logged in user using parameterisation
string query = "SELECT ProxyStatus.ProxyStatusId, ProxyStatus.FunctionId, ProxyStatus.StartDate, ProxyStatus.EndDate, ProxyStatus.IsActive FROM ProxyStatus INNER JOIN Staff ON Staff.StaffId = ProxyStatus.Proxee WHERE (Staff.StaffId = #StaffId)";
DateTime thisDay = DateTime.Today;
SqlCommand myCommand = new SqlCommand(query, myConnection);
myCommand.Parameters.AddWithValue("#staffid", staffid);
SqlDataReader rdr = myCommand.ExecuteReader();
if (rdr.HasRows)
{
while (rdr.Read())
{
Session["StartDate"] = rdr["StartDate"].ToString();
Session["EndDate"] = rdr["EndDate"].ToString();
Session["ProxyStatusId"] = rdr["ProxyStatusId"].ToString();
Session["FunctionId"] = rdr["FunctionId"].ToString();
// Get the session of StartDate and endate, use the session value in a query to compare against the current date
string startdate = Session["StartDate"].ToString();
string enddate = Session["EndDate"].ToString();
string proxystatus = Session["ProxyStatusId"].ToString();
DateTime startdatedata = Convert.ToDateTime(startdate);
DateTime enddatedata = Convert.ToDateTime(enddate);
if (startdatedata > thisDay)
{
string DefaultConnection2 = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
SqlConnection myConnection2 = new SqlConnection(DefaultConnection2);
myConnection2.Open();
string query2 = "UPDATE ProxyStatus SET ProxyStatus.IsActive = 'False' WHERE ProxyStatus.ProxyStatusId = #proxystatus";
myCommand.Parameters.AddWithValue("#newproxystatus", proxystatusnew);
SqlCommand myCommand2 = new SqlCommand(query2, myConnection2);
myCommand2.ExecuteNonQuery();
}
}
}
else
{
rdr.Close();
}
}
}
}
Shouldn't the lines be
SqlCommand myCommand2 = new SqlCommand(query2, myConnection2);
myCommand.ExecuteNonQuery();
be
SqlCommand myCommand2 = new SqlCommand(query2, myConnection2);
myCommand2.ExecuteNonQuery();
instead? The first "myCommand" will still be in use with "rdr".

How to set NCHAR to null with an update statement (C# sqlcommand)

I'm wondering how to set an nchar column to null with an update statement. I found this: NULL value for int in Update statement
which says you have to cast to set non-int fields to NULL.
So I tried the following:
commandText =
#"UPDATE Brukere
SET Engangskode = CAST(NULL AS NCHAR)
WHERE Navn = #navn AND Mobilnr = #mobilnr";
However, when I execute this it still won't update the column to NULL. Am I casting wrong, or is it something else? Any help would be appreciated :)
Longer code snip if needed: http://pastebin.com/8auKuk6Q
The problem is that you are setting the local variable commandText to the update statement instead of the command.CommandText. Change it to the following
command.CommandText = "UPDATE Brukere SET Engangskode=NULL WHERE Navn=#navn AND Mobilnr=#mobilnr";
And I think it will work with or without the casting.
I would recommend NOT to "re-use" the SqlCommand in your example - create a new, specific command for the UPDATE statement, something like this:
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
string bruker = Request.Cookies["Navn"].Value;
string mobilnr = Request.Cookies["Mobilnr"].Value;
string commandText = "SELECT Engangskode FROM Brukere WHERE Navn=#navn AND Mobilnr=#mobilnr";
bool correctCode = false;
try
{
using (SqlCommand command = new SqlCommand(commandText, con))
{
.....
if (correctCode)
{
// DO NOT "reuse" the previous SqlCommand - create a new, specific one!
string updateQuery = "UPDATE Brukere SET Engangskode = NULL WHERE Navn = #navn AND Mobilnr = #mobilnr;";
using (SqlCommand updateCmd = new SqlCommand(updateQuery, con)
{
updateCmd.Parameters.Add("#navn", SqlDbType.NVarChar, 20).Value = bruker;
updateCmd.Parameters.Add("#mobilnr", SqlDbType.NChar, 10).Value = mobilnr;
updateCmd.ExecuteNonQuery();
Response.Redirect("Kvittering.aspx", false);
}
}
}
}
catch( .... )
{
.......
}
}
No need to cast. Juse set column = null. NO quotes, tho!

efficient way to apply operator on specific record in MsAccess Database

public void moveBooks(int quantityOfMovedBooks, int booksID)
{
int finalQuantityOfBooks = totalBooksInDB(booksID) - quantityOfMovedBooks;
queryString = "update Books set bQuantity='" + finalQuantityOfBooks + "'where bID=" + booksID;
myComm = new OleDbCommand(queryString, myConn);
myConn.Open();
myComm.ExecuteNonQuery();
myConn.Close();
}
public int totalBooksInDB(int bID)
{
int booksQuantity;
queryString = "select bQuantity from Books where bID=" + bID;
myComm = new OleDbCommand(queryString, myConn);
myConn.Open();
booksQuantity = (int)myComm.ExecuteScalar();
myConn.Close();
return booksQuantity;
}
im beginner in MSAccess Database and C#, im maintaing a Table in which there are 3 fields one is BookID, second is BookName, third is BookQuantity.. scope is when books are moved to aisle books should be subtracted from main inventory.. im using this approach.. but i wonder is there any better or efficient way of doing this..
thanx in advance
A couple of changes.
First, never use string concatenation to build sql command text. This leads to sql injection attacks. A very serious security problem
Second, your code for getting the number of books could result in a null value returned by ExecuteScalar and thus you will get an error
Third. The connection should be opened when needed, used, and then closed and disposed. Your code will fail to close and dispose the connection if, for whatever reason, you get an exception.
The using statement prevent this issue taking care to close and dispose of the connection also in case of exceptions.
Fourth well this is more a logical problem. I think that you can't move more books than those stored in the inventory, so add a check just to be safe-
public void moveBooks(int quantityOfMovedBooks, int booksID)
{
int quantity = totalBooksInDB(booksID);
if(quantity > quantityOfMovedBooks)
{
int finalQuantityOfBooks = quantity - quantityOfMovedBooks;
queryString = "update Books set bQuantity=? where bID=?";
using ( OleDbConnection myConn = new OleDbConnection(GetConnectionString() )
using ( OleDbCommand myComm = new OleDbCommand(queryString, myConn))
{
myComm.Parameters.AddWithValue("#p1", finalQuantityOfBooks);
myComm.Parameters.AddWithValue("#p2", booksID);
myConn.Open();
myComm.ExecuteNonQuery();
}
}
else
MessageBox.Show("Invalid quantity to move");
}
public int totalBooksInDB(int bID)
{
int booksQuantity = 0;
queryString = "select bQuantity from Books where bID=?";
using ( OleDbConnection myConn = new OleDbConnection(GetConnectionString() )
using ( OleDbCommand myComm = new OleDbCommand(queryString, myConn))
{
myComm = new OleDbCommand(queryString, myConn);
myComm.Parameters.AddWithValue("#p1", bID);
myConn.Open();
object result = myComm.ExecuteScalar();
if(result != null)
booksQuantity = Convert.ToInt32(result);
}
return booksQuantity;
}

Categories