сервер asp.net/sql попробуй поймать что происходит? - PullRequest
1 голос
/ 29 июля 2009

Я обнаружил ошибку в своем коде, и я озадачен тем, как она могла произойти.

Мой вопрос: я обнаружил пропуск в полях идентификатора базы данных (это увеличенное поле идентификатора), указывающий на то, что некоторые записи не были вставлены - это означает, что мои SQL-спроки (вероятно) выдавали ошибку. Думая в обратном направлении, это означает, что мой бизнес-объект должен был отловить эту ошибку и выдать ее, немедленно выйдя из нее и вернувшись к коду страницы (вместо этого он продолжил прямо до второй хранимой процедуры). Я не понимаю, почему или как это возможно. Что происходит в отношении выполнения кода, пропускающего мои попытки отлова?

Код страницы позади:

 protected void submitbutton_click(object sender, EventArgs e){
      try{
        mybusinessobject.savetodatabase()
      } catch( Exception ex) {
        Response.Redirect("Error.aspx");
      }
 }

код бизнес-объекта:

 public static void savetodatabase(){
        int ID1=-1;
        int ID2=-1;
        //store the billing contact
        SqlCommand cmd1 = new SqlCommand("SaveInfo1", con);
        cmd1.CommandType = CommandType.StoredProcedure;
        //...
        cmd1.Parameters.Add("@Ret", SqlDbType.Int);
        cmd1.Parameters["@Ret"].Direction = ParameterDirection.ReturnValue;

        try
        {
            con.Open();
            cmd1 .ExecuteNonQuery();
            ID1 = Convert.ToInt32(cmd1.Parameters["@Ret"].Value);
        }
        catch (Exception ex) { throw ex; }
        finally { con.Close(); }

        if (ID1  > 0)
        {
            SqlCommand cmd = new SqlCommand("SaveInfo2", con);
            cmd.CommandType = CommandType.StoredProcedure;
            //...
            try
            {
                con.Open();
                cmd.ExecuteNonQuery();
                ID2= Convert.ToInt32(cmd.Parameters["@Ret"].Value);
            }
            catch (Exception ex) { throw ex; }
            finally { con.Close(); }
        }
 }

Код SQL:

PROCEDURE [dbo].[SaveInfo1]
( 
-- ... parameters ...
)
AS
    INSERT INTO Table1 ( ... ) Values ( ... )
RETURN SCOPE_IDENTITY

PROCEDURE [dbo].[SaveInfo2]
( 
-- ... parameters ...
)
AS
    DECLARE @SpecialID INT
    INSERT INTO Table2 ( ... ) Values ( ... )
    SET @SpecialID = SCOPE_IDENTITY()
    INSERT INTO Table3 ( [ID],  ... ) Values ( @SpecialID, ... )
RETURN SCOPE_IDENTITY()

Ответы [ 5 ]

2 голосов
/ 30 июля 2009

Ваша обработка исключений ужасна. Никогда сделать это:

catch (Exception ex) { throw ex; }

Все, что вам нужно, это испортить трассировку стека в исключении. Это выглядит как исключение, возникшее в точке throw.

Никогда сделать это:

  try{
    mybusinessobject.savetodatabase()
  } catch( Exception ex) {
    Response.Redirect("Error.aspx");
  }

Вы не знаете, что произошло исключение. Вы понятия не имеете, безопасно ли перенаправлять или нет, и, кроме того, вы теряете всю информацию о том, что было исключением!

Вы должны также привыкнуть к реализации блоков using:

public static void savetodatabase()
{
    using (SqlConnection con = new SqlConnection("Connectionstring"))
    {
        int ID1;
        //store the billing contact
        using (SqlCommand cmd1 = new SqlCommand("SaveInfo1", con))
        {
            cmd1.CommandType = CommandType.StoredProcedure;
            //...
            cmd1.Parameters.Add("@Ret", SqlDbType.Int);
            cmd1.Parameters["@Ret"].Direction = ParameterDirection.ReturnValue;

            con.Open();
            cmd1.ExecuteNonQuery();
            ID1 = Convert.ToInt32(cmd1.Parameters["@Ret"].Value);
        }

        if (ID1 <= 0)
        {
            return;
        }

        int ID2 = -1;
        using (SqlCommand cmd = new SqlCommand("SaveInfo2", con))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            //...
            con.Open();
            cmd.ExecuteNonQuery();
            ID2 = Convert.ToInt32(cmd.Parameters["@Ret"].Value);
        }
    }
}

Блок using гарантирует, что для ресурса будет вызван метод Dispose, независимо от того, было ли выброшено исключение.

0 голосов
/ 29 июля 2009

вы можете проверить улов. просто измените процедуру:

PROCEDURE [dbo].[SaveInfo1]
( 
-- ... parameters ...
)
AS
    INSERT INTO Table1 ( ... ) Values ( ..., some_out_of_range_value_here, ....)
RETURN SCOPE_IDENTITY()

чтобы иметь жестко запрограммированное значение вне диапазона (поэтому вставка не удалась), а затем запустить ваше приложение ...

0 голосов
/ 29 июля 2009

Если записи удалены, их уникальные идентификаторы не будут повторно использованы, даже если позже будут добавлены новые записи. Вы можете использовать RESEED в SQL, чтобы сбросить начальное значение идентификатора до 0, если хотите, но я советую против этого, если вы не сотрете таблицу. В противном случае вы можете получить нарушения первичного ключа.

Кроме того, убедитесь, что начальное значение идентификатора вашего столбца установлено на единицу за раз.

0 голосов
/ 29 июля 2009

Ваш код не имеет значения, просто зайдите в Web.config и поиграйте с соответствующим узлом:

<customErrors mode="On|Off" />

P.S. Используйте предложение using для автоматического закрытия соединения вместо ручного в предложении finally

0 голосов
/ 29 июля 2009

Не является ли более вероятным сценарий, что кто-то просто удалил некоторые записи из таблицы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...