C# and SQL beginner here. I have two tables using primary key of table1 as a foreign key in table2. To get an ID, I'm using SELECT MAX and everything works as I want (code below):
{
con1.Open();
SqlCommand cmd1 = new SqlCommand();
cmd1.CommandText = "INSERT INTO dbo.testDriver(name) Values(@name)";
cmd1.Connection = con1;
cmd1.Parameters.AddWithValue("@name", name.Text);
cmd1.ExecuteNonQuery();
cmd1.Parameters.Clear();
cmd1.CommandText = "SELECT MAX(PkDriverID) FROM dbo.testDriver";
int FkDriverID = Convert.ToInt32(cmd1.ExecuteScalar());
cmd1.CommandText = "INSERT INTO dbo.testCar(brand, model, FkDriverID) Values(@brand, @model, @FkDriverID)";
cmd1.Connection = con1;
cmd1.Parameters.AddWithValue("@brand", brand.Text);
cmd1.Parameters.AddWithValue("@model", model.Text);
cmd1.Parameters.AddWithValue("@FkDriverID", FkDriverID);
cmd1.ExecuteNonQuery();
cmd1.Parameters.Clear();
con1.Close();
}
{
Response.Redirect(this.Request.Url.ToString());
}
But colleagues are telling me I should use SCOPE_IDENTITY() instead of SELECT MAX. I do understand why should I use it (in case of multiple users, etc.) but after replacing SELECT MAX with it, I get an error:
Object cannot be cast from DBNull to other types.
In my database, PKs and FK have int datatype, Nulls are not allowed and with SELECT MAX it just works. So what am I doing wrong here?
In race conditions
Select MAXmay return ID generated by someone else right after your insert. Moreover,identitydoes not have to grow eternally - it may bereseededor even turned back to negatives. Also it does inappropriate additionalselectwork.SCOPE_IDENTITYis the only right way for your (and for most of all other's) case.Furthermore, I'd recommend to put two queries into single one and surround both inserts with a transaction. This way you'll be able to
rollbackchanges toDriverif something went wrong with aCar.