The INSERT statement conflicted with the FOREIGN KEY constraint FK_Kupovina_Kupac. The conflict occurred in database OnlineApoteka, table dbo.Kupac, column 'ID'.
The statement has been terminated.
I'm really confused I do not know why we do not allow? I reported a bug, in throw ex; ?
public static void Kupi(long lekID, int kolicina, double cena, long nacinIsporukeID, string korisnickoIme)
{
SqlConnection con = new SqlConnection();
try
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["OnlineApotekaConnectionString"].ConnectionString;
con.Open();
string updateLager = #"
UPDATE Lager
SET Kolicina=Kolicina-#Kolicina
WHERE LekID=#LekID";
SqlCommand cmd = new SqlCommand(updateLager, con);
cmd.Parameters.AddWithValue("#LekID", lekID);
cmd.Parameters.AddWithValue("#Kolicina", kolicina);
cmd.ExecuteNonQuery();
string insertIntoKupovina=#"
INSERT INTO Kupovina (KupacID, LekID, Datum, Kolicina, Cena, NacinIsporukeID)
VALUES (#KupacID, #LekID, #Datum, #Kolicina, #Cena, #NacinIsporukeID)";
cmd = new SqlCommand(insertIntoKupovina, con);
cmd.Parameters.AddWithValue("#KupacID", KupacAdapter.GetID(korisnickoIme));
cmd.Parameters.AddWithValue("#LekID", lekID);
cmd.Parameters.AddWithValue("#Datum", DateTime.Now.Date);
cmd.Parameters.AddWithValue("#Kolicina", kolicina);
cmd.Parameters.AddWithValue("#Cena", cena);
cmd.Parameters.AddWithValue("#NacinIsporukeID", nacinIsporukeID);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
}
I have a routine event for the button Buy.
When you click Kupi, should be removed from the table Lager volumes and placed in the Kupac Kupovina
protected void kupiButton_Click(object sender, EventArgs e)
{
KupovinaAdapter.Kupi(Convert.ToInt64(kupovinaGreedView.SelectedDataKey["LekID"].ToString()),
Convert.ToInt32(kolicinaTextBox.Text),
Convert.ToInt64(kupovinaGreedView.SelectedDataKey["Cena"].ToString()),
Convert.ToInt64(nacinIsporukeDropDownList.SelectedValue),
User.Identity.Name);
}
protected void kupovinaGreedView_SelectedIndexChanged(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(kupovinaGreedView.SelectedDataKey["Lek"].ToString()))
{
LekLabel.Text = kupovinaGreedView.SelectedDataKey["Lek"].ToString();
}
if (!String.IsNullOrEmpty(kupovinaGreedView.SelectedDataKey["Kolicina"].ToString()))
{
kolicinaValidator.MaximumValue = kupovinaGreedView.SelectedDataKey["Kolicina"].ToString();
}
The reason you are getting the error is because of how the database schema is defined. In particular the table Kupac is used in a relation with the table Kupovina such that the KupacID in Kupovina must match a value from the ID field in the Kupac table.
Because of this you cannot insert records into the Kupovina table using a KupacID that doesn't already exist in the Kupac table - it's a Foreign-Key Constraint violation.
You have two options:
make sure you first insert a record into the Kupac table
drop the foreign-key constraint from the database schema if that makes business-sense
But you should examine the output of the KupacAdapter.GetID(korisnickoIme) which is what is supposed to provide the KupacID value. If this method for some reason does not return a valid ID (one from the Kupovina table) than the insert will fail as explained above.
In case you are wondering why the Exception is not begin "handled" than that is because of the code in your catch block. You are basically taking the exception and re-throwing it which is sort of pointless. You might as well just not have a catch block at all..
try {
// ...
}
catch (Exception ex) {
throw ex; // <--- this just re-throws the same exception that was caught!
}
finally {
}
Is, for the most part, nearly equivalent to:
try {
// ...
}
finally {
}
The difference is only in how much of the stack trace is preserved along with the exception, but the exception is bubbled up nonetheless.
The Kupac table does not have the KupacID value in that table that you are trying to insert into the Kupovina table
The KupacID column in the Kupac table is the primary key, while the KupacID column in the Kupovina table is the foreign key pointing back to the primary key
Read up on Foreign Keys
Yes, you are catching the key violation with catch (Exception ex) - however you then rethrow the Exception there.
Do you have an error handler in the calling routine?
throw ex - does not "handle" an error - it is simply raising another (although, the same one in this case - the one that has been caught)
If you are expecting this specific error then you should catch this specific error by catch (SqlException ex) - and then check for this particular error. If it is not this error then throw ex; back up the call-stack... If it is this error then you can ignore (but it would be better to just avoid this kind of INSERT in the first place...)
Related
I'm inserting a Tag when it already exists into the Tag table, hence it returns the message,
Message "Cannot insert duplicate key row in object 'dbo.Tag' with unique index 'IX_Tag_Name'. The duplicate key value is (Lemon).\r\nThe statement has been terminated." string
I've tried to catch this Unique exception by checking for the Number 2601 but am unable to access the Number property.
Apparently this is how you are suppose to catch the exception but ex.InnerException.InnerException is null, so the switch statement never executes.
How can I catch UniqueKey Violation exceptions with EF6 and SQL Server?
catch (DbUpdateException ex)
{
if (ex.InnerException.InnerException is SqlException sqlException)
{
switch (sqlException.Number)
{
// If the tag already exists
case 2601: // Unique Key violation
}
}
}
Your code is checking the inner exception of your inner exception. This is null, and hence your code is failing. Instead do:
catch (DbUpdateException ex)
{
if (ex.InnerException is SqlException sqlException)
{
switch (sqlException.Number)
{
// If the tag already exists
case 2601: // Unique Key violation
}
}
}
I will like to know how to catch the exception for this error message.
I tried to delete a record from a table, but the table has a FK from another table.
Thank you in advance!
Try below code:
try
{
//Your code block to delete the record.
}
catch(Exception ex)
{
if (ex.Message.ToLower().Contains("statement conflicted with the reference constraint"))
{
//Show custom error message as "need to delete parent value before delete this record."
}
}
I want to know how we identify the primary key duplication error from SQL Server error code in C#.
As a example, I have a C# form to enter data into a SQL Server database, when an error occurs while data entry, how can I identify the reason for the error from the exception?
If you catch SqlException then see its number, the number 2627 would mean violation of unique constraint (including primary key).
try
{
// insertion code
}
catch (SqlException ex)
{
if (ex.Number == 2627)
{
//Violation of primary key. Handle Exception
}
else throw;
}
MSSQL_ENG002627
This is a general error that can be raised regardless of whether a
database is replicated. In replicated databases, the error is
typically raised because primary keys have not been managed appropriately across the topology.
This is an old thread but I guess it's worth noting that since C#6 you can:
try
{
await command.ExecuteNonQueryAsync(cancellation);
}
catch (SqlException ex) when (ex.Number == 2627)
{
// Handle unique key violation
}
And with C#7 and a wrapping exception (like Entity Framework Core):
try
{
await _context.SaveChangesAsync(cancellation);
}
catch (DbUpdateException ex)
when ((ex.InnerException as SqlException)?.Number == 2627)
{
// Handle unique key violation
}
The biggest advantage of this approach in comparison with the accepted answer is:
In case the error number is not equal to 2627 and hence, it's not a unique key violation, the exception is not caught.
Without the exception filter (when) you'd better remember re-throwing that exception in case you can't handle it. And ideally not to forget to use ExceptionDispatchInfo so that the original stack is not lost.
In case of Entity Framework, the accepted answer won't work and the error will end up not being caught. Here is a test code, only the entity catch statement will be hit or of course the generic exception if entity statement removed:
try
{
db.InsertProcedureCall(id);
}
catch (SqlException e0)
{
// Won't catch
}
catch (EntityCommandExecutionException e1)
{
// Will catch
var se = e1.InnerException as SqlException;
var code = se.Number;
}
catch (Exception e2)
{
// if the Entity catch is removed, this will work too
var se = e2.InnerException as SqlException;
var code = se.Number;
}
Working code for filter only duplicate primary key voilation exception
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
.........
try{
abc...
}
catch (DbUpdateException ex)
{
if (ex.InnerException.InnerException is SqlException sqlEx && sqlEx.Number == 2601)
{
return ex.ToString();
}
else
{
throw;
}
}
Note fine detial :- ex.InnerException.InnerException not ex.InnerException
I have a legacy method that keeps throwing an exception. It has a nested try|catch. Is this the best way to code that sort of thing:
public void DBCommand(string dynSQL, bool Silent)
{
checkConnection(); //Despite the name, this "returns" void, not bool
SqlCeCommand cmd = objCon.CreateCommand();
SqlCeTransaction trans = GetConnection().BeginTransaction();
cmd.Transaction = trans;
try
{
cmd.CommandText = dynSQL;
cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex)
{
try
{
trans.Rollback();
}
catch (SqlCeException sqlceex)
{
MessageBox.Show(string.Format("SqlCeException ({0})", sqlceex.Message));
CCR.LogMsgs.Append(string.Format("SqlCeException exception: {0}\r\n", sqlceex.Message));
// Handle possible Rollback exception here
}
MessageBox.Show(string.Format("DBCommand Except ({0})", ex.Message));
CCR.LogMsgs.Append(string.Format("DBCommand exception: {0}\r\n", ex.Message));
}
}
?
I want to refactor this to use using statements for at least the SqlCeCommand, but for now the above is the "as-is" code. I'm seeing the general exception message
("DBCommand Except"), never the "SqlCeException"
UPDATE
By adding some MessageBox.Show() calls back (debug log file no longer being written for some reason), I found that this is the DDL that throws the exception:
ALTER TABLE CCR032713190114 ADD salvationId nvarchar(19), salvation float
Note: "CCR032713190114" has been proven to be a valid tablename (it exists) at this point in thecode.
Is there something wrong with this DDL that would cause a problem?
UPDATE 2
I changed the code from this:
ddl = string.Format("ALTER TABLE {0} ADD salvationID nvarchar(19) ", tablename);
dbconn.DBCommand(ddl,false);
ddl = string.Format("UPDATE {0} SET salvationID = {1}", tablename, string.Empty);
...to this:
ddl = string.Format("ALTER TABLE {0} ADD salvationID nvarchar(19) NOT NULL WITH DEFAULT", tablename);
dbconn.DBCommand(ddl,false);
...but now, right after "ALTER TABLE BLA ADD salvation float NOT NULL WITH DEFAULT" I'm seeing this err msg, "DBCommand Except (There was an error parsing the query.
[Token line number, Token line offset,, Token in error,,])"
What in Azure braziers is going on here?
Do I need to specify a default val after the "WITH DEFAULT" (won't '' or string.empty automatically be the default for a nvarchar column, 0.0 for a float, etc.)?
You cannot add two columns in same ALTER TABLE statement, must add one at a time, also good idea to specify NULL or NOT NULL (if NOT NULL, a DEFAULT may be required)
If you do not ever see the SqlCeException then it would truly be exceptional. To keep it 'out of the way', I would do the following:
public void DBCommand(string dynSQL, bool Silent) {
checkConnection(); //Despite the name, this "returns" void, not bool
SqlCeCommand cmd = objCon.CreateCommand();
SqlCeTransaction trans = GetConnection().BeginTransaction();
cmd.Transaction = trans;
var doRollback = false;
try {
cmd.CommandText = dynSQL;
cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex) {
doRollback = true
MessageBox.Show(string.Format("DBCommand Except ({0})", ex.Message));
CCR.LogMsgs.Append(string.Format("DBCommand exception: {0}\r\n", ex.Message));
}
finally {
if(doRollback) }
DoRollback();
}
}
}
void DoRollback(){
try {
trans.Rollback();
}
catch (SqlCeException sqlceex) {
MessageBox.Show(string.Format("SqlCeException ({0})", sqlceex.Message));
CCR.LogMsgs.Append(string.Format("SqlCeException exception: {0}\r\n", sqlceex.Message));
// Handle possible Rollback exception here
}
}
}
I want to tell the user that a record was not deleted because it has child data, but how can I be sure that the exception was thrown because of a foreign key violation? I see that there a sqlexception class that is used for all sql exception.
Assume you're using SQL Server.
Using teh web archive - https://web.archive.org/web/20190120182351/https://blogs.msdn.microsoft.com/tomholl/2007/08/01/mapping-sql-server-errors-to-net-exceptions-the-fun-way/
try
{
# SQL Stuff
}
catch (SqlException ex)
{
if (ex.Errors.Count > 0) // Assume the interesting stuff is in the first error
{
switch (ex.Errors[0].Number)
{
case 547: // Foreign Key violation
throw new InvalidOperationException("Some helpful description", ex);
break;
case 2601: // Primary key violation
throw new DuplicateRecordException("Some other helpful description", ex);
break;
default:
throw new DataAccessException(ex);
}
}
}
Case 547 is your man.
UPDATE The above is sample code and should not be used. Please follow the link as to explain why.
You can write your exception-expected code in the Try block if any exception will be thrown it will be catch further now you can get error number.now can check is it a Foreign Key violation or not
try
{
//your deletetion code
}catch (SqlException ex)
{
if (ex.Errors.Count > 0) // Assume the interesting stuff is in the first error
{
switch (ex.Errors[0].Number)
{
case 547: // Foreign Key violation
lblError.Text = "Cannot Delete this Record this is associated with other record...!";
break;
default:
throw;
}
}
}