【问题标题】:Stored procedure won't return 0存储过程不会返回 0
【发布时间】:2011-01-10 18:11:04
【问题描述】:

这是我的sp

CREATE PROCEDURE DeteleTitle
(
@TitleID int
)
AS
BEGIN
IF EXISTS(Select TitleID from Titles WHERE TitleID=@TitleID)
BEGIN
DELETE FROM Titles WHERE  TitleID=@TitleID
SELECT @TitleID
END
ELSE
BEGIN
SELECT 0
END
END

我称之为的方法是:-

public Int32 DeleteTitle(Int32 TitleID)
{
try
{
int ds=0;
SqlParameter[] sqlparam=new SqlParameter[1];
sqlparam[0]=(@TitleID,TitleID);
ds=Convert.ToInt32(SqlHelper.ExecuteScalar(ConfigurationManager.ConnectionStrings["con"].ConnectionString,CommandType.StoredProcedure,"DeleteTitle",sqlparam).Tables[0]);
return ds;
}

catch(Exception ex)
{
return 0;
}
}

现在 TitleID 是许多表中的外键。如果某个表的记录正在使用 TitleID,那么它会抛出这个异常,上面写着“Foreign Key Violation n stuff”。在我上面的存储过程中,我在 else 块中选择零,以防删除不成功。当删除成功时,它返回 TitleID 的值,如 50、99 或其他值。现在发生的事情是,当删除不成功时,它不会返回零。我希望根据 Delete Stored 过程返回的零值在屏幕上显示一条消息,但是当它没有返回任何值(删除失败时)时,我在 DeleteTitle() 方法的 catch 块中返回零。

现在我有两个问题:-

  1. 为什么删除失败时存储过程不返回零?
  2. 在 catch 块中返回零是否像我在上面所做的那样正确?我不知道您如何检索外键异常号和其他内容,所以我只是在 catch 块中返回零。

【问题讨论】:

  • 您至少应该捕获一个 sqlexception(我相信这是正确的,如果不查找的话)。目前,您可能会在此处捕获各种不相关的异常,而只是忽略它们。您应该真正捕获特定异常,以便任何意外的异常都可以冒泡到应用程序级别的错误处理程序以进行适当的处​​理和记录以及其他任何事情。

标签: c# asp.net sql-server stored-procedures


【解决方案1】:

您需要在您的过程中使用TRY...CATCH,而不是 IF...ELSE。

如果您考虑一下,当 DELETE 因外键违规而失败时,您已经处于语句的 IF 部分。你的代码怎么可能跳转到 ELSE 块?

【讨论】:

    【解决方案2】:

    问题是如果您的 if 语句因异常而失败,它将不会执行 ELSE 语句。你的 IF 语句也显示不正确——不应该是 IF EXISTS,[然后删除记录?] 现在写的方式,如果记录存在,它不会被删除。

    扩展的问题是,依赖异常(在 C#、SQL 或任何其他语言中)作为流控制方法被认为是不好的做法。

    您最好通过对每个相关表使用 EXISTS 语句来显式检查相关记录。

    【讨论】:

    • 你是对的..它只是如果存在..是一个错字..我已经更正了。一个问题 - 许多表使用 TitleID 作为外键有什么方法?仍然在所有这些表中显式检查?请回答..thnx
    【解决方案3】:

    如果Tables 是表的集合,则您需要另一个[0] 用于第一个表的第一列。

    【讨论】:

    • 在我看来,Tables 实际上是 Execute Scalar 方法返回的“对象”。我希望它在那里抛出一个异常(或者可能实际上没有编译),因为在返回的对象上不会有一个名为“Table”的属性或方法。不过我可能是错的。 :)
    【解决方案4】:

    使用这个:

    CREATE PROCEDURE DeteleTitle
    (
    @TitleID int
    )
    AS
    BEGIN TRY
        DELETE FROM Titles WHERE TitleID=@TitleID
        SELECT CASE 
                   WHEN @@ROWCOUNT>0 THEN @TitleID 
                   ELSE 0 --row did not exist
               END
    END TRY
    BEGIN CATCH
        SELECT 0 --delete failed
    END CATCH
    go
    

    当多个表通过外键“链接”并且您删除父行时,您会收到与报告类似的错误,因为没有父数据就不能存在子数据。您可能希望查看级联删除,或在此过程中添加代码以从通过外键与 Titles 关联的表中删除。在DELETE FROM Titles 之前添加这些删除。这样做:

    CREATE PROCEDURE DeteleTitle
    (
    @TitleID int
    )
    AS
    BEGIN TRY
        BEGIN TRANSACTION
    
        DELETE FROM YourOtherTablesA WHERE TitleID=@TitleID
        DELETE FROM YourOtherTablesB WHERE TitleID=@TitleID
    
        DELETE FROM Titles WHERE TitleID=@TitleID
        SELECT CASE 
                   WHEN @@ROWCOUNT>0 THEN @TitleID 
                   ELSE 0 --row did not exist
               END
        COMMIT
    END TRY
    BEGIN CATCH
        IF XACT_STATE()!=0
        BEGIN
            ROLLBACK TRANSACTION
        END
        SELECT 0 --delete failed
    END CATCH
    go
    

    【讨论】:

      【解决方案5】:

      您可以使用@@ERROR 作为输出结果。 @@ERROR = 0 表示成功否则操作不成功

      CREATE PROCEDURE DeteleTitle
      (
          @TitleID int
      )
      AS
      
      BEGIN
          IF EXISTS(Select TitleID from Titles WHERE TitleID=@TitleID)
          BEGIN
              DELETE FROM Titles WHERE  TitleID=@TitleID      
          END
      
          Select @@ERROR
      
      END
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-16
        • 2016-06-19
        • 2017-07-12
        相关资源
        最近更新 更多