3

I am letting the user able to delete a specific record in a SQL table. The problem is that I want to set the id(automatically) to the last id sequence presented into the db after the deletion. ex(delete item 14,when I add another item the id of that item won't be 15 but 14 because after the delete I've reset the id to 13 which is the last one after the delete)

private void btnCanc_Click(object sender, RoutedEventArgs e)
{


 sqliteCon.Open();
  try
  {
    string Test = null;//estrazione1

    SqlCommand q = new SqlCommand("DELETE FROM tabSE  WHERE idSE =" + txtIDL.Text.ToString(), sqliteCon);
    //string q = "DELETE FROM tabSE  WHERE idSE =" + txtIDL.Text.ToString();

    SqlCommand q1 = new SqlCommand("DELETE FROM tabL  WHERE idL =" + txtIDL.Text.ToString(), sqliteCon);
    //string q1 = "DELETE FROM tabL  WHERE idL =" + txtIDL.Text.ToString();

    SqlCommand q2 = new SqlCommand("DELETE FROM tabSD  WHERE id =" + txtIDL.Text.ToString(), sqliteCon);
    //string q2 = "DELETE FROM tabSD  WHERE id =" + txtIDL.Text.ToString();


    q.ExecuteNonQuery();
    q1.ExecuteNonQuery();
    q2.ExecuteNonQuery();



    SqlCommand m = new SqlCommand("SELECT idL  FROm tabL", sqliteCon);
    SqlDataReader idLRdr = null;//estrazione2
    idLRdr = m.ExecuteReader();//estrazione3
    while (idLRdr.Read())//estrazione4
    {
      Test = idLRdr["idL"].ToString();//estrazione5
    }

    SqlCommand r = new SqlCommand("DBCC CHECKIDENT(tabL,tabSE,tabSD,RESEED,'" + Test + "')", sqliteCon);  
    r.ExecuteNonQuery();

    SqlCommand r1 = new SqlCommand("DBCC CHECKIDENT(tabL,RESEED,'" + Test + "')", sqliteCon);
    r1.ExecuteNonQuery();
    SqlCommand r2 = new SqlCommand("DBCC CHECKIDENT(tabSE,RESEED,'" + Test + "')", sqliteCon);
    r2.ExecuteNonQuery();
    SqlCommand r3 = new SqlCommand("DBCC CHECKIDENT(tabSD,RESEED,'" + Test + "')", sqliteCon);
    r3.ExecuteNonQuery();
  }
  catch (SqlException ex)
  {
    MessageBox.Show(ex.Message);
  }
  MessageBox.Show("Dato Cancellato Correttamente");
  sqliteCon.Close();

}

code improved but it update the value of the id of the table but not the real id of each table(idL,idSE,id)(those are my custom ids)

OK I'VE MADE MY TESTS,THE PROBLEM IS THAT THE ID'S OF EACH TABLE(idL(TABLE tabL),idSE(TABLE tabSE),id(TABLE tabSD))AREN'T UPDATED BY MY CODE DBCC WHILE THE ID'S OF EACH TABLE(THOSE WHICH AREN'T CUSTOM MADE) ARE UPDATE AUTOMATICALLY... I NEED TO UPDATE idL,idSE,id

Peregrine
  • 4,287
  • 3
  • 17
  • 34
codroipo
  • 155
  • 12
  • 1
    You should execute your command somewhere. – Ralf Mar 27 '19 at 09:18
  • Creating a command and not executing it has no effect. All your commands are not executed. IE no ExecuteNonQuery called – Steve Mar 27 '19 at 09:18
  • ohhhh ok should i do a executeno query for every query and should those executenoquery be in order of execution? – codroipo Mar 27 '19 at 09:19
  • And apart from that above, why do you need to reseed the identity counter? Usually IDs are of no interest to your user and serve only to setup the primary key/ foreign key relationships – Steve Mar 27 '19 at 09:19
  • because i've got checkboxes from the db to the a datagrid if the id aren't perfect it broke everything – codroipo Mar 27 '19 at 09:25
  • read above,i've updated the code – codroipo Mar 27 '19 at 09:27
  • What database are you using? the connection variable is called _sqlite_ but the code uses the Sql Server client library. – Steve Mar 27 '19 at 09:38
  • it's only a name i'm using sql – codroipo Mar 27 '19 at 09:50
  • Please do not add images containing error messages : https://meta.stackoverflow.com/questions/285551/why-not-upload-images-of-code-on-so-when-asking-a-question – Fourat Mar 27 '19 at 10:06
  • but i need to let everyone see what kind of problem i'm speacking about – codroipo Mar 27 '19 at 10:10
  • This code is full of sql injection problems. Don't put code like this where you are putting together sql using input from ui controls directly. It would be better if you used a stored procedure and passed validated parameters. – Kevin Cook Mar 27 '19 at 11:33

2 Answers2

3

Of course the first problem is the fact that you don't execute the commands, but there are a lot of things that could be improved in your code. First and foremost is the concatenation of strings to build a sql command. This leads to problems with parsing and to the dangerous Sql Injection trick used to hack a databases. I have changed your code to use a parameter and avoid these problems.

The second improvement is given by the ability to execute batch commands. In other words you can put all your command texts in a single string and separate each one using a semicolon. Then just execute the command only one time and everything will be executed by the database engine.

But the real problem in your code is the DBCC CheckIdentity RESEED part. This part requires you to know which value to set as the new Identity because the RESEED option without a new value works only if the next identity value is lower than the current max value in the IDENTITY column, moreover this could be done safely only if you have exclusive access to the database (I mean, none is adding records to these tables while you get the MAX value for the ID)

sqliteCon.Open();
try
{
    string sqlText = @"DELETE FROM tabStoreExec  WHERE idSE = @idse;
                       DELETE FROM tabList  WHERE idL = @idse;
                       DELETE FROM tabStoricoDetail  WHERE id = @idse";
   SqlCommand q = new SqlCommand(sqlText, sqliteCon);
   q.Parameters.Add("@idse", SqlDbType.Int).Value = Convert.ToInt32(txtIDL.Text);
   q.ExecuteNonQuery();


   // This is the point where you change the identity.
   // To minimize concurrency problems we execute a stored procedure instead 
   sqlText = "ResetIdentity";
   q.CommandText = sqlText;
   q.CommandType = CommandType.StoredProcedure;
   q.Parameters.Clear();
   q.ExecuteNonQuery();
   MessageBox.Show("Dato Cancellato Correttamente");
}
catch (SqlException ex)
{
   MessageBox.Show(ex.Message);
}
sqliteCon.Close();

This is the possible code for your stored procedure, note that I don't know what is the name of the IDENTITY column in your tables. For this example I have used always id as the name for the IDENTITY column

create procedure ResetIdentity
as
    begin
    declare @maxval integer

    set @maxval = (select MAX(id) from tabStoreExec);
    dbcc checkident('tabStoreExec', RESEED, @maxval);

    set @maxval = (select MAX(id) from tabStoricoDetail);
    dbcc checkident('tabStoricoDetail', RESEED, @maxval);

    set @maxval = (select MAX(id) from tabList);
    dbcc checkident('tabList', RESEED, @maxval);
end 

There is another improvement to your code and it is related to the using statement to create disposable objects like the database connection. The correct usage of such objects should be something like this

using(SqlConnection sqlConn = new SqlConnection(......))
{
     sqlConn.Open();
     .... do you database code here ....
} // This will close and dispose the connection
Steve
  • 213,761
  • 22
  • 232
  • 286
  • @madcodroipo you need to try it. – Steve Mar 27 '19 at 09:53
  • i've updated the image,with the output of your code that sadly gives me me the same problem – codroipo Mar 27 '19 at 10:03
  • maybe the problem is another, i can now update the id of the table but i can't update the id of each table,idL,idSE and id (my custom ids) – codroipo Mar 27 '19 at 10:12
  • I see, the problem in the code is that you want to reset the id. This point is complicated. Do you have concurrent connection to the database? Changing the IDENTITY nextval should be done when there is exclusive access to the database otherwise someone could insert a record while you are in the process of changing the IDENTITY to a lower value. – Steve Mar 27 '19 at 11:28
  • oh ok the db is local and it will follow the code wherever he is so doesn't matter if the db is secure or not,i want to allow to you to see the problem but...can we KIT throgh this mail? (codroipomad@gmail.com) so i can send u the images of the db – codroipo Mar 27 '19 at 12:07
  • only want to solve this problem cause it is destroying my mind, i'm near a thousand of lines of code only for this admin partition – codroipo Mar 27 '19 at 12:12
  • and to specify i don't wanto to reset the id (idL=0) i wanto to reset the id to the last id in the table after the delete...if i delete the item12 and then i'll add another item,that item has to be idL,idSE,id=12 and not idL,idSE,id=13 – codroipo Mar 27 '19 at 12:21
  • In the Stored Procedure code I will get the maximum value of the IDENTITY column you want to Reseed. I have used the name _id_ for this column, but of course you need to replace it with the name of the IDENTITY column in your tables. What's wrong with that? – Steve Mar 27 '19 at 12:26
  • ah ok ok perfect,give me a sec – codroipo Mar 27 '19 at 12:26
  • where do i have to put (create procedure ResetIdentity as...) – codroipo Mar 27 '19 at 12:29
  • and it's in that block that i have to modify the id?right? – codroipo Mar 27 '19 at 12:29
  • You use Sql Server Management Studio, select your database, open a new query window, paste the code of the SP and click Execute. Yes you change the names there. Or, in Visual Studio use Sql Server Explorer, create or use the connection to your database, right click on Stored Procedure and add a new stored procedure with the text above, Execute it. – Steve Mar 27 '19 at 12:32
  • sorry for those odd questions but i'm doing things that i don't know very well...but doing that i'm understanding a lot of new things – codroipo Mar 27 '19 at 12:33
  • so 'esplora server',click on my db and...(from visual studio) – codroipo Mar 27 '19 at 12:35
  • okok found but where do i have to save that stored procedure?inside the folder of the app?if yes thene where? – codroipo Mar 27 '19 at 12:41
  • The SP is saved inside the database after you press the Execute (Right click on the SP window and select Execute) It become part of your database like a Table or a View or other objects that you can add to it. – Steve Mar 27 '19 at 12:49
0

i will go as well with what @Steve said , the ID here is for the table (PK,FK)relation , why don't just add another field of sequential numbers that you update using LINQ as desired . and also your code is missing the query execution command ,

SqlCommand q = new SqlCommand("DELETE FROM tabStoreExec  WHERE idSE =" + 
txtIDL.Text.ToString(), sqliteCon);
//string q = "DELETE FROM tabStoreExec  WHERE idSE =" + txtIDL.Text.ToString();
q.ExecuteNonQuery();

 OR

con.Open();

using (SqlCommand q= new SqlCommand("DELETE FROM tabStoreExec  WHERE idSE =" + txtIDL.Text.ToString(), sqliteCon))

  {
       q.ExecuteNonQuery();
  }

con.Close();

Wesam
  • 932
  • 3
  • 15
  • 27