I'm trying to do a very simple INSERT using VB.NET. For some reason I'm getting a SqlException on every insert though. The data is inserted, but still get the following:
Violation of PRIMARY KEY constraint 'PK_User'. Cannot insert duplicate key in object 'dbo.Employee'. The statement has been terminated
When I check in SQL Management Studio, the data is succesfully inserted.
Here is the code where the problem is happening
Try
conn.Open()
Dim insertSQL As String = "insert into Employee(uName, firstName, lastName,
On_Switch, On_Phone) " + "values('" & uName & "', '" & firstName & "', '" _
& lastName & "', '" & onSwitch & "', '" & onPhone & "')"
Dim AddCom As SqlCommand = New SqlCommand(insertSQL, conn)
If (AddCom.ExecuteNonQuery() = 1) Then
lblError.Text = "User Added."
' string urlBack = "../ViewAsset.aspx?DeptID=" + DeptID;
' Response.Redirect(urlBack);
End If
conn.Close()
Catch ex As SqlException
Dim ExMsg As String = ex.Message.ToString()
lblError.Text = ExMsg
I went back and tested the same code in C# and there is no Exception thrown. It seems to be something small I'm doing in VB, but I'm lost as to what it is.
As a side note, I STRONGLY recommend changing to parameterized queries to prevent the risk of SQL injection that your current code is not protected from.
For the error issue, I would check to see that your code isn't being called twice in the VB version.
Two theories. Either your code is being executed twice, or there's a trigger on the Employee table that's attempting an insert following the successful insert. (Edit: #Mitchel Sellers is exactly right, if the same code works in c# it's absolutely not a trigger issue.)
My hunch is that your code is being executed twice. Try running with the debugger attached and a breakpoint set on the ExecuteNonQuery - I think you'll find that some other method calls this method multiple times.
#Mitchel Sellers - GOOD CATCH ON THE SQL INJECTION BUG! Parameters, please!
As another side note, I noticed that your code could potentially leave a sql connection open. If you're using the .NET 2.0 framework you should use the Using statement. It ensures that connections are closed and disposed even if an exception is thrown. Check this article on MSDN for more detail: http://msdn.microsoft.com/en-us/library/htd05whh.aspx. The other option would be to add the close statement in a Finally block of your try-catch handler.
If you are executing this code within an event of some sort make sure you have not subscribed to the event multiple times. I have had this problem in asp.net. Usually I just delete the click event handler in the code behind and the onclick attribute in the aspx file if it exists there as well and then try it again.
Related
I use Try-Catch to skip some error-prone SQL command in C# but I sometimes still get an execution/runtime error.
My C# code to work with a SQL server database will run frequently. On the first run, there's somewhere in my code that I try to update a table which doesn't exist yet (Later on in the code the table in discussion will be created). I put the part of query in a try-catch, but sometimes still get the error that Invalid object name 'destination_table'.
My code is like this:
string query_str =
" BEGIN TRY " +
" UPDATE [my_DB].[dbo].[destination_table] " +
" SET the_column = 'the_value' " +
" END TRY " +
" BEGIN CATCH " +
" END CATCH ";
using (SqlCommand my_command = new SqlCommand(query_str , conn))
{ form_rack_command.ExecuteNonQuery(); }
The solutions in this link seem good SQL: Try/Catch doesn't catch an error when attempting to access a table that it can't find
But my problem is that I can't always reproduce the error. It seems like sometimes when I start my computer and open Microsoft Visual Studio, I get the error on the first run of the program. But not even shutting down the system and restart everything can always cause the error.
What can be the reason that sometimes I have this problem and sometimes not?
I'm working on a project for a college course I'm currently on and I'm having some trouble trying to insert data into a database from an application developed in Visual Studio 2017. I've already connected to the database and am able to open it from the application.
The issue arises when I try to enter data into the table. I get a syntax error. Usually this means there an issue with the actual command right? Well i thought about this and created a new database, and another project and got the inert into command working for that one. At this point , a week of trying to get it to work, I'm stuck and desperately need help. Here is the code I'm using to try and add data to the table.
try
{
Form1.DataBaseConnection.Open();
}
catch (Exception E)
{
MessageBox.Show("!!ATTENTION!! - Error accessing database. Please restart the application. ::::" + E.ToString());
Form1.DataBaseConnection.Close();
}
OleDbCommand DataBaseAddEntry = new OleDbCommand();
DataBaseAddEntry.Connection = Form1.DataBaseConnection;
DataBaseAddEntry.CommandText = "insert into Shoe(Size, Type, Name) values('" + int.Parse(TxtBoxSize.Text) + "','" + TxtBoxType.Text + "','" + TxtBoxName.Text + "')";
DataBaseAddEntry.ExecuteNonQuery();
Form1.DataBaseConnection.Close();
RefreshDataGridView();
As a side not, I didn't design the database or create it. I have to work in a team and the database was created by another member. So when I created my own database it worked fine. Could it be something to do with the actual database and not the code?
Try removing the single quotes from the value for Size, as this looks like it should be an int types.
DataBaseAddEntry.CommandText = "insert into Shoe([Size], [Type], [Name]) values(" + int.Parse(TxtBoxSize.Text) + ",'" + TxtBoxType.Text + "','" + TxtBoxName.Text + "')";
Also, as the comment suggests, you should use parameterized SQL and consider wrapping the try block over the whole database operation, and not only the attempt to open.
I am currently writing my first .Net & C# application with Visual Studio, and have a need to write generated values to MySQL from the application.
At present, I can write values fine - but I need to be able to check to see if a value exists and display that line if it does exist, otherwise insert new line to table. My connection string is defined at the top of the form.
I have the following defined already, and it writes to the database successfully if no duplicate values exist in the LicenseKey column. If a duplicate exists, it throws an unhandled exception.
private void SaveDetails()
{
// MySQL 'insert' command
string InsertNewLicense = "insert into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values('" +this.textBoxLicenseeName.Text+ "','" +this.textBoxComputerName.Text+ "','" +this.textBoxContactName.Text+ "','" +this.textBoxContactEmail.Text+ "','" +this.textBoxLicenseKey.Text+ "','" +this.textBoxCreationDate.Text+ "');";
//MySQL instance details
MySqlConnection InsertLicenseDetails = new MySqlConnection(LicenseDatabaseConnection);
//MySQL command execution
MySqlCommand InsertCommand = new MySqlCommand(InsertNewLicense, InsertLicenseDetails);
// Handles command outputs.
MySqlDataReader InsertReader;
//Opens connection to run query on database
InsertLicenseDetails.Open();
// Here our query will be executed and data saved into the database.
MessageBox.Show("License Details Saved. Please ensure you have emailed the license to the customer.");
while (InsertReader.Read())
{
}
InsertLicenseDetails.Close();
}
What I want to happen is for a check to be run on the LicenseKey column to see if the value exists, before different actions are taken.
If the value does not exist, I would like to insert the new line to the table (like my existing command does).
If, however, the value does exist, I would like to pop up a form showing the values from the line that the duplicate appears in as a form.
Where would I put in an event handler to read MySQLException values? What exception would I have to respond to for a duplicate value or no database response?
I agree with what the others have said in their comments, you could change the SQL Query to do the check instead of having 2.
IF(SELECT ... WHERE A = B)
RETURN THAT THE VALUE ALREADY EXISTS
ELSE
INSERT NEW VALUE
Also there was a good comment about SQL Injection and parameterized queries. The query string should look a bit more like
INSERT into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values(#LicenseeName, #ComputerName, #ContactName ...);
and your SqlCommand be parameterized
InsertCommand.Paramaters.AddWithValue("#LicenseeName", this.textBoxLicenseeName.Text);
InsertCommand.Paramaters.AddWithValue("#ComputerName", this.textBoxComputerName.Text);
...
That should be a good start to get you going.
After looking at the queries for a while I decided to try a different tack - instead of using a direct check if it's there, I opted to use a count(*) query. When I click the save button on the form, the buttonClick_event calls SaveDetails(), which runs the following:
private void SaveDetails()
{
string InsertNewLicense = "INSERT into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values(#LicenseeName, #ComputerName, #ContactName, #ContactEmail, #LicenseKey, #CreationDate)";
string LicenseExistence = "SELECT COUNT(*) FROM BCOM.LicenseDetails WHERE LicenseKey LIKE #LicenseKey";
MySqlConnection LicenseDetails = new MySqlConnection(LicenseDatabaseConnection);
MySqlCommand InsertCommand = new MySqlCommand(InsertNewLicense, LicenseDetails);
InsertCommand.Parameters.AddWithValue("#LicenseeName", this.textBoxLicenseeName.Text);
InsertCommand.Parameters.AddWithValue("#ComputerName", this.textBoxComputerName.Text);
InsertCommand.Parameters.AddWithValue("#ContactName", this.textBoxContactName.Text);
InsertCommand.Parameters.AddWithValue("#ContactEmail", this.textBoxContactEmail.Text);
InsertCommand.Parameters.AddWithValue("#LicenseKey", this.textBoxLicenseKey.Text);
InsertCommand.Parameters.AddWithValue("#CreationDate", this.textBoxCreationDate.Text);
MySqlCommand QueryCommand = new MySqlCommand(LicenseExistence, LicenseDetails);
QueryCommand.Parameters.AddWithValue("#LicenseKey", this.textBoxLicenseKey.Text);
MySqlDataReader InsertReader;
LicenseDetails.Open();
if ((int)(long)QueryCommand.ExecuteScalar() >0)
{
MessageBox.Show("This license already exists in the database.");
}
else
{
InsertReader = InsertCommand.ExecuteReader();
MessageBox.Show("License Details Saved. Please ensure you have emailed the license to the customer.");
while (InsertReader.Read())
{
}
}
LicenseDetails.Close();
So, if the query against the license keys returns with any results at all (more than 0 rows returned), a messagebox pops up showing that the key already exists. If the resultant number of rows is 0, the insert command gets run.
This was figured out with a look through MySQL command notes, testing with phpMyAdmin, matching against existing projects online, and support from the following:
The SELECT query was figured out with great support from #Seige.
The query was parameterized with help from Seige, following on from the advice of Sani Huttunen. Many thanks to them both.
Changing to the count method was done on the advice of a fellow coder in another community online - a good friend and brilliant coder.
I have a project that is used by several clients but for one of them using sql server 2005 wherever any code that runs a sql statement which includes a date like so:
" AND ABS.AbsenceDate = '" + DateTime.Now.ToString("yyyy-MM-dd") + "'";
I get the error: The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
This only happens for this one client/server, if I copy the actual sql string created and execute it in Sql Server on this server it runs ok. I created a test page to ensure the date string was correct and did indeed display as 2013-11-26 as expected. My assumption was that the app was sending the date as 2013-26-11 as this would cause the issue but then the test showed otherwise so leaves me stumped.
For info, this is on an English server so the regional setting is day/month/year and dates stored as year-month-day etc
Don't concatenate strings to build your sql string but sql-parameters. The main reason is to prevent sql-injection but it can also prevent localization- or conversion issues like this.
string sql = #"SELECT Columns
FROM dbo.tableName
WHERE ...
AND ABS.AbsenceDate = #AbsenceDate";
using(var con = new SqlConnection("ConnectionString"))
using(var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("#AbsenceDate", DateTime.Today);
con.Open();
using(var reader = cmd.ExecuteReader())
{
while(reader.Read())
{
// ...
}
}
}
I have solved the issue and quite surprised at what the problem was. I was able to run the sql ok in management studio but I was logged in using Windows Authentication. I realised I should try with the account the app uses and when logged in as this I did get the error.
Turns out whoever set the account up had the Language set to British English. I changed it to English and voila problem solved.
Never mind the added security, Sql Parameters would solve your problem automatically.
Is there a date part for that date or is it irrelevant ?
An example solution would be the following:
" AND ABS.AbsenceDate = Convert(DateTime, '" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "', 20) "'
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Obtain the Query/CommandText that caused a SQLException
I am working on some error handling code (using elmah) and the default setup only sends the error message. I would like to know the actual SQL that throws an error (i.e. "SELECT * FROM thisTableDoesNotExist")
This is what I have so far:
if (e.Error.Exception is SqlException)
{
//if SQL exception try to give some extra information
SqlException sqlEx = e.Error.Exception as SqlException;
e.Mail.Body = e.Mail.Body + "<div>" +
"<h1>SQL EXCEPTION</h1>" +
"<b>Message</b>: " + sqlEx.Message +
"<br/><b>LineNumber:</b> " + sqlEx.LineNumber +
"<br/><b>Source:</b> " + sqlEx.Source +
"<br/><b>Procedure:</b> " + sqlEx.Procedure +
"</div>";
}
And I would like to be able to also show the actual SQL. The database is SQL Server 2008 and SqlException is of type System.Data.SqlClient.SqlException.
Not possible. You'll need to catch the exception where the SQL command was executed, and then include your command text in your own custom exception. See Obtain the Query/CommandText that caused a SQLException.
You could have error handling code in your SQL, and when it encounters an error, you can send back the SQL that it attempted to run with a print or returns statement or however you want to return it to your application.
The best way to examine the exception is to put a breakpoint in your code where the exception happens and examine the values of the exception object graph.
Try the Message member of the InnerException like this:
sqlEx.InnerException.Message
It may not provide the exact SQL that failed but may give you more specific information such as the operation and the table name. The StackTrace member may also have some information.
If you can't get enough information on C# side you can use "SQL profiler" (part of complete MS SQL) to see what commands where executed.
Information on SQL Profiler http://msdn.microsoft.com/en-us/library/ms181091.aspx . You should also be able to use underlying Tracing API if you don't have profiler - http://msdn.microsoft.com/en-us/library/ms191006.aspx