C# Update Table using SqlCommand.Parameters - c#

I'm trying to update an MSSQL table using SqlCommand, I think it's a syntax error with my T-SQL, but here is what I have so far:
SqlCommand sqlCmd = new SqlCommand("UPDATE yak_tickets SET email = #emailParam, subject = #subjectParam, text = #textParam, statusid = #statusIDParam, ticketClass = #ticketClassParam WHERE id = #ticketIDParam", sqlConn);
The parameters are working as they should, however, the table never gets updated when I run the code. Any help would be appreciated =)
Here is the rest of the code:
#region Parameters
/* Parameters */
sqlCmd.Parameters.Add("#ticketIDParam", SqlDbType.BigInt);
sqlCmd.Parameters["#ticketIDParam"].Value = ticketID;
sqlCmd.Parameters.Add("#emailParam", SqlDbType.NVarChar);
sqlCmd.Parameters["#emailParam"].Value = ticketToBeSubmitted.getEmail();
sqlCmd.Parameters.Add("#subjectParam", SqlDbType.NVarChar);
sqlCmd.Parameters["#subjectParam"].Value = ticketToBeSubmitted.getSubject();
sqlCmd.Parameters.Add("#textParam", SqlDbType.Text);
sqlCmd.Parameters["#textParam"].Value = ticketToBeSubmitted.getTicketContent();
sqlCmd.Parameters.Add("#statusIDParam", SqlDbType.NVarChar);
sqlCmd.Parameters["#statusIDParam"].Value = ticketToBeSubmitted.getStatus();
sqlCmd.Parameters.Add("#ticketClassParam", SqlDbType.NVarChar);
sqlCmd.Parameters["#ticketClassParam"].Value = ticketToBeSubmitted.getTicketClass();
#endregion
#region Try/Catch/Finally
/* Try/Catch/Finally */
try
{
sqlConn.Open();
sqlCmd.ExecuteNonQuery();
}
catch (SqlException sqlEx)
{
sqlErrorLabel.Text = sqlEx.ToString();
sqlErrorLabel.ForeColor = System.Drawing.Color.Red;
}
finally
{
sqlConn.Close();
}
And the method's signature:
public static void updateTicketInDatabase(Ticket ticketToBeSubmitted, Label sqlErrorLabel, int ticketID)

UPDATE FROM is invalid syntax (edit: OP corrected this). The problem might also be the "text" column. text is a keyword in SQL Server, since it's a datatype. Try putting brackets around it.
UPDATE yak_tickets
SET email = #emailParam,
subject = #subjectParam,
[text] = #textParam,
statusid = #statusIDParam,
ticketClass = #ticketClassParam
WHERE id = #ticketIDParam

Had to use if(!Page.IsPostBack)

Couple of questions:
Is this inside of a transaction thats getting rolledback?
Have you verified that you #ticketIDParam matches a set of rows on the table? Especially if its not just a integer key
Are you updating rows that have no side effects (i.e. your updating to the same values)?
Can you provide the paramaters.Add statements for this query
Is there a trigger or other setting on the table (I assume not, as you did not mention anything).
You said you know the params are working correctly, can you say how you verified this? (profiler, visual inspection, etc).

Sounds like your hosting provider limits your debug options, forcing you to do it the old fashioned way. What if immediately after the update, you put something like:
;SELECT ##ROWCOUNT
then instead of ExecuteNonQuery, do ExecuteScalar, and see if SQL even thinks its updated anything.

Related

C# code to insert values into a database not working

This is the button for inserting those fileds into my database, the field names and db connection works for any other tasks but somehow this button keeps telling me the insert failed"
private void button1_Click(object sender, EventArgs e)
{
try {
int answer;
sql = "INSERT INTO Registration VALUES (#Student_ID,#Course_ID,#Section,#Start_Date,#End_Date,#Semester)";
connection.Open();
command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("#Student_ID", comboBox1.SelectedItem.ToString());
command.Parameters.AddWithValue("#Course_ID", lstcourse.SelectedItem.ToString());
command.Parameters.AddWithValue("#Section", txtsection.Text);
command.Parameters.AddWithValue("#Start_Date", txtstart.Text);
command.Parameters.AddWithValue("#End_Date", txtend.Text);
command.Parameters.AddWithValue("#Semester", txtsemester.Text);
answer = command.ExecuteNonQuery();
command.Dispose();
connection.Close();
MessageBox.Show("You're awesome and added " + answer + " row to your registration");
}
catch
{
MessageBox.Show("You screwed up");
}
/////////////////////////////////
}
This is the table:
Registration_ID float Checked
Student_ID float Checked
Course_ID float Checked
Section float Checked
Start_Date datetime Checked
End_Date datetime Checked
Semester nvarchar(255) Checked
Unchecked
Somehow this button keeps telling me the insert failed
It would of been helpful if you could have posted the actual error from the catch statement. If you debugged the routine and specifically inspected the error message, you'd notice what was wrong.
The primary issue of the error is because you didn't supply the columns to insert into. If you supplied all columns upfront the insert statement would be satisfied and work just fine.
Solution
Either make sure all columns are accounted for in the insert statement.
Specify the columns you are inserting into.
Your table according to your post has 7 columns, you are only supplying 6 of them. When you using the syntax of INSERT INTO TABLENAME VALUES() you have to supply values for all columns, not just a select few.
On the other hand if you used the syntax of INSERT INTO TABLENAME(columnName, columnName)VALUES(value, value) you are fulfilling the requirements by supplying two columns along with their values.
Side Note:
Look into using statements to ensure objects are disposed of.
Use SqlParameterCollection.Add method instead of AddWithValue, it has to infer the data types and this could cause unintended results.
When declaring your parameters, please specify/add the correct data type and length that matches the column data type and length on the table.
Either modify your SQL statement to include the missing column:
INSERT INTO Registration VALUES (#Registration_ID,#Student_ID,#Course_ID,#Section,#Start_Date,#End_Date,#Semester)
or specify the columns that will be populated in your new row (assuming your Registration_ID field is an auto-identifier)
INSERT INTO Registration (Student_ID, Course_ID, Section, Start_Date, End_Date, Semester) VALUES (#Student_ID,#Course_ID,#Section,#Start_Date,#End_Date,#Semester)
you can try this code
using(SqlConnection connection = new
SqlConnection(ConfigurationManager.ConnectionStrings["conString"].ConnectionString))
{
connection.Open();
string sql = "INSERT INTO Table(id,name,test)
VALUES(#param1,#param2,#param3)";
using(SqlCommand cmd = new SqlCommand(sql,connection))
{
cmd.Parameters.Add("#param1", SqlDbType.Int).value = val;
cmd.Parameters.Add("#param2", SqlDbType.Varchar, 50).value = Name;
cmd.Parameters.Add("#param3", SqlDbType.Varchar, 50).value = Test;
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}

MS SQL Can't update table

I have a one column table to keep track of number of visits. In Global.asax.cs I attempt to increment this value by 1 inside application_start but the field does't get updated. I get no exceptions but number of rows affected is always zero.
I tried the same simple query in SSMS and I get the same thing: 0 rows affected.
There is one int column in that table called NumVisits.
This is part of Application_Start in Global.asax.cs:
Application.Lock();
int iNumVisits = SomeClass.GetNumVisits();
SomeClass.UpdateNumVists(iNumVisits + 1);
Application.UnLock();
This is in SomeClass (BLL):
public static void UpdateNumVists(int iNumVisists)
{
LocaleRepository oLocaleRepository = new LocaleRepository(new SqlDbContext());
oLocaleRepository.UpdateNumVists(iNumVisists);
}
and this is in DAL:
public void UpdateNumVists(int iNumVisits)
{
int iRet = 0;
try
{
dbContext.Open();
List<SqlParameter> spParams = new List<SqlParameter>();
string sQuery = "update Visits set NumVisits = #NumVisits";
spParams.Add(dbContext.CreateSqlParam("#NumVisits", SqlDbType.Int, 0, iNumVisits));
dbContext.ExecuteSqlNonQuery(sQuery, spParams, ref iRet);
}
catch (Exception e)
{
throw e;
}
finally
{
dbContext.Close();
}
return;
}
I use the following for all commands using executeNonQuery:
public void ExecuteSqlNonQuery(string sQuery, List<SqlParameter> spParams, ref int iRet)
{
using (SqlCommand command = new SqlCommand())
{
command.CommandType = CommandType.Text;
command.Parameters.AddRange(spParams.ToArray<SqlParameter>());
command.Connection = DbConnection;
command.CommandText = sQuery;
try
{
iRet = command.ExecuteNonQuery();
}
catch(Exception e)
{ }
}
}
when the update command is executed, iRet is zero. I can't see why a simple update query would not work.
This is the create script I got from SSMS:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Visits](
[NumVisits] [int] NULL
) ON [PRIMARY]
GO
In general there are a few possible reasons why an update would not happen.
First, if the field is also an identity or calculated field, an ordinary update is not going to work. This doesn't look to be your case, but it is good to know for the future.
Next if there is a trigger on the table, it may be preventing the update. SSMS doesn't necessarily script triggers out when you script a table, so I can't tell if you have a trigger.
Third And most common, your application may not be sending what you expect as the update statement or even communicating with the database at all when you expect it to. This is often true when there is a problem of nulls. If your variable is not properly populating, then you may indeed be updating a null value to a null value. Run Profiler to capture exactly what is being sent when you try to do the update. Often when you see the statement that is actually being run, you will see the problem. Sometimes it is a matter of a missing space, sometimes a variable that was not populated that you thought was populated, etc.
Another possibility is that the user running the code has no update rights to the table. You should have gotten a message if this were the case.
If you have run Profiler, try running that exact code in SSMS and see if it updates. Sometimes you get a better error bubble up when you do that. Especially if your error handling in the application code is not well designed.
Of course if the table has no data, you need to do an insert not an update. Or the update might not be finding any records to update, try doing a select using the same conditions and it may turn out there is not record to update.
It seems like there is no data in the table, are there any records in Visits?

how to get the value of certain selected value out from Stored Procedure

i just got started with ASP.Net, i only knew PHP so which means im a little stubborn. i need real examples.
heres my problem, i got this class in a class library called Class1, it connects to the database and ask for verification of user login.
public string userlogin(string loginuser,string loginpass)
{
string type = null;
myCon.Open();
SqlCommand logincheck = new SqlCommand("CheckID", myCon);
logincheck.CommandType = CommandType.StoredProcedure;
logincheck.Parameters.Add("#userid", SqlDbType.NVarChar).Value = loginuser;
logincheck.Parameters.Add("#password", SqlDbType.NVarChar).Value = loginpass;
SqlDataReader dr;
dr = logincheck.ExecuteReader();
while (dr.Read())
{
type = //here i want to get the value of type in my database
break;
}
myCon.Close();
return type;
}
here's my stored procedure
ALTER PROCEDURE dbo.logincheck
#userid nchar(10),
#password nchar(20)
AS
Select * from users Where userid = #userid and password = #password
RETURN
i need a set of examples please.
Without knowing how your users table is structured, the following is a guess:
while (dr.Read()) {
...
}
should be changed to:
if (dr.Read()) {
type = dr["type"].ToString();
}
A couple of recommendations.
Use using clauses around your connection and command objects. This will save you a lot of pain later. See: Calling stored procedure with return value for an example. And SqlConnection SqlCommand SqlDataReader IDisposable for the reasons why. Hint: if the code as you have it now was released into production it is highly likely you will begin to see random database related exceptions start popping up in various places. So this is pretty important.
The name of the proc in your SqlCommand ("checkid") doesn't match the actual name of your stored procedure ("logincheck"). Change one of them. What you have right now will result in a sql error when executed.
Consider changing the name of the variable type. Type is a class in the System namespace and the way that reads is a bit confusing. Maybe accountType, loginType, userType or something similar. You can certainly leave it as type; just people following you will question it.
Change your select statement to actually name the columns you want back. As it stands it's brittle. See: What is the reason not to use select *?
I used an if statement instead of a while because you really only want the first row.
Assuming "UserType" is the column you are looking for (can't tell because you are using a Select *) that line would be
type = dr["UserType"] as string

SQL Server CE WHERE statement behaving wrong? very confused

I am developing a windows mobile app. Right now I am just testing that it can correctly query the local SQL Server CE database. It works fine until I put a WHERE statement in.
Here is my code:
private void buttonStart_Click(object sender, EventArgs e)
{
System.Data.SqlServerCe.SqlCeConnection conn = new System.Data.SqlServerCe.SqlCeConnection(
("Data Source=" + (System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "ElectricReading.sdf") + ";Max Database Size=2047")));
try
{
// Connect to the local database
conn.Open();
System.Data.SqlServerCe.SqlCeCommand cmd = conn.CreateCommand();
SqlCeParameter param = new SqlCeParameter();
param.ParameterName = "#Barcode";
param.Value = "%" + textBarcode.Text.Trim() + "%";
// Insert a row
cmd.CommandText = "SELECT * FROM Main2 WHERE Reading LIKE #Barcode";
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
DataTable data = new DataTable();
using (SqlCeDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
data.Load(reader);
}
}
if (data != null)
{
this.dataGrid1.DataSource = data;
}
}
finally
{
conn.Close();
}
The database contains this data:
Okay so you can see I changed the WHERE statement to use the Reading column just for testing purposes. When I enter "111" into the textbox and run --> it returns only the row where reading ="1111" and not the row that contains "111".
If I enter "1111" it does not return any data.
If I enter "1" it will return both the "1111" row and the "111" row which is the correct behavior.
However if I enter "11" it once again only returns the "1111" row.
Any other data entry of 2's or 9's attempting to return those rows does not work.
I'm not sure what is going on? This does not make any sense. It is not behaving like I would expect in any way shape or form. I know this must be a little confusing to read. I hope it makes enough sense to get some answers. Please help!
NOTE: I added the "%" before and after the text in an attempt to get better results. This is not desired.
EDIT <<<-----------------------I did have Reading = #Barcode, I just accidently typed Location for this question, that is not the problem.
Firstly, some things to note:
1) As other commentators have noted, use the Reading column, not the Location column. I know you have mentioned you are testing, but swapping around column names and then changing code isn't the easiest way to troubleshoot these things. Try to only change one thing at a time.
2) If Reading is numeric, you are going to have to convert the column value first.
So your query becomes:
"SELECT * FROM Main2 WHERE CONVERT(varchar, Reading) LIKE #Barcode";
Also see How to use parameter with LIKE in Sql Server Compact Edition for more help with working with parameters in SqlServerCE.
3) Set a parameter type on your SqlCEParameter. I've linked to the appropriate page in the code example below.
4) You are using ExecuteNonQuery for no reason. Just get rid of it in this context. It's for when you want to make a change to the database (like an insert, update, delete) or execute something (like a stored proc that can also insert, update, delete etc) that returns no rows. You've probably cut and paste this code from another place in your app :-)
5) Use using on disposable objects (see example below). This will make managing your connection lifecycle much simpler. It's also more readable (IMO) and will take care of issues when exceptions occur.
6) Use the using statement to import the BCL (Base Class Libraries) into your current namespace:
Add the following using statements to the top of your class (.cs). This will make using all of the .Net classes a lot simpler (and is much easier to read and less wear on your keyboard ;-)
using System.Data.SqlServerCe;
using System.IO;
using System.Reflection;
A more complete example would look like the following
private void buttonStart_Click(object sender, EventArgs e)
{
using(SqlCeConnection conn = new SqlCeConnection(
("Data Source=" + (Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase), "ElectricReading.sdf") + ";Max Database Size=2047"))))
{
// Connect to the local database
conn.Open();
using(SqlCeCommand cmd = conn.CreateCommand())
{
SqlCeParameter param = new SqlCeParameter();
param.ParameterName = "#Barcode";
param.DBType = DBType.String; //Intellisense is your friend here but See http://msdn.microsoft.com/en-US/library/system.data.sqlserverce.sqlceparameter.dbtype(v=VS.80).aspx for supported types
param.Value = "%" + textBarcode.Text.Trim() + "%";
// SELECT rows
cmd.CommandText = "SELECT * FROM Main2 WHERE CONVERT(varchar, Reading) LIKE #Barcode";
cmd.Parameters.Add(param);
//cmd.ExecuteNonQuery(); //You don't need this line
DataTable data = new DataTable();
using (SqlCeDataReader reader = cmd.ExecuteReader())
{
data.Load(reader); //SqlCeDataReader does not support the HasRows property.
if(data.Rows.Count > 0)
{
this.dataGrid1.DataSource = data;
}
}
}
}
}
Intellisense should be able to clean up any errors with the above but feel free to ask for more help.
Finally, you also might be able to set the data source of the grid directly to a datareader, try it!
using (SqlCeDataReader reader = cmd.ExecuteReader())
{
dataGrid1.DataSource = reader;
}
You can then get rid of the DataTable.
Change the following line:
cmd.CommandText = "SELECT * FROM Main2 WHERE Location LIKE #Barcode";
to
cmd.CommandText = "SELECT * FROM Main2 WHERE Reading LIKE #Barcode";
You are comparing the wrong columns.

Calling a stored procedure using C#

private void btnGo_Click(object sender, EventArgs e)
{
Array IDlist = txtUserID.Text.Split(new char[] { });
ArrayList badID = new ArrayList();
foreach (string textLine in IDlist)
{
try
{
int LineID = Convert.ToInt32(textLine);
string emp = txtDistricts.Text;
command.Parameters.Add("#EmpID", SqlDbType.Int).Value = LineID;
if (!emp.Equals(string.Empty))
command.Parameters.Add("#SchoolDistricts", SqlDbType.NVarChar).Value = emp;
else command.Parameters.Add("#SchoolDistricts", SqlDbType.NVarChar).Value = DBNull.Value;
if (cbRemove.Checked)
command.Parameters.Add("#Options", SqlDbType.Int).Value = 1;
else if (cbReset.Checked)
command.Parameters.Add("#Options", SqlDbType.Int).Value = 0;
else command.Parameters.Add("#Options", SqlDbType.Int).Value = DBNull.Value;
SqlParameter returnValue = new SqlParameter("#return_value", DbType.String);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
conn.Open();
command.Connection = conn;
// command.ExecuteNonQuery();
command.ExecuteScalar();
String OutPutCheck = (command.Parameters["#return_value"].Value.ToString());
String getCheck = (command.ExecuteScalar().ToString());
OPBox.Text += LineID + "--->>" + OutPutCheck + "--->>" + getCheck + "\n";
conn.Close();
//flagUser(LineID, emp);
}
catch (Exception ex)
{
//stored procedure error
badID.Add(textLine);
conn.Close();
}
}}
I made an APP , which takes bunch of ID at a time. After btn_click these values put in array. Then from array each ID pass to store procedure one by one, and get return value. well First value give return value, but after that when second value pass to store procedure it gives following error.
> ERROR::::ex = {"Procedure or function
> usp_Flag_Employee has too many
> arguments specified."}
You keep adding parameters to your command object without reseting it. You should move your connection and command objects into the method where they are being called and use 'using' statements.
Because your connection and command are class fields, each instance of the loop is re-adding the parameters to the old set of parameters. At minimum, reset the parameters collection at the top of the loop.
You are passing too many parameters to the procedure. If you paste the procedure code we can help identify, however just do a count of the params and check to ensure you have all defined in the proc.
I don't see any code generating the SqlCommand object in your example.
If command is local to the class, there's a very good chance that it has already been used (which means it probably already has parameters added to it).
I also see no code that sets the command type to StoredProcedure. Depending on what the command text is, this could be the issue as well (if you're simply passing the stored procedure name without setting the type...it will see the command as having no parameters).
Re-Writing the code to use its own SqlConnection and SqlCommand would make this much easier to debug (unless, of course, it already is and you didn't give us that code).
EDIT
I just noticed that you're using the code inside a foreach loop without clearing the parameters. That is yet another issue (and probably the most likely cause for this issue). Just be sure to call command.Parameters.Clear() at the beginning of each loop before adding the new parameters.
Call the Clear method before adding the parameters.
It works the first time because your command object has no parameters. For each subsequent iteration you keep on adding another set of parameters to your command object.
You need to clear the parameters for your command object on each iteration.

Categories

Resources