代码之家  ›  专栏  ›  技术社区  ›  Ing. Jose Valera

使用Mediator的.NET 7中的SqlException问题

  •  0
  • Ing. Jose Valera  · 技术社区  · 1 年前

    我正在尝试捕获存储过程抛出的错误,在某些情况下,这些错误会验证信息,如果它返回 RAISEERROR ,但它不进入 SqlException 在捕获中。

    这是我的程序:

    CREATE PROCEDURE CivilStatusSave
        (@CivilStatusId CHAR(1), 
         @CivilStatusName NVARCHAR(15),
         @CreateBy NVARCHAR(60),
         @CreationDate DATETIME,
         @ModifiedBy NVARCHAR(60),
         @ModifiedDate DATETIME)
    AS
    BEGIN
        SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
        SET NOCOUNT ON;
    
        BEGIN TRY
            IF EXISTS (SELECT 1 FROM CivilStates AS cs 
                       WHERE cs.CivilStatusId = @CivilStatusId)
            BEGIN
                RAISERROR('Ya se encuentra un registro en el sistema, con este codigo', 12, 1);
                RETURN;
            END
            
            IF EXISTS (SELECT 1 FROM CivilStates AS cs 
                       WHERE UPPER(cs.CivilStatusName) = UPPER(@CivilStatusName))
            BEGIN
                RAISERROR('Ya se encuentra un registro en el sistema, con este estado civil', 12, 1);
                RETURN;
            END
    
            INSERT INTO CivilStates (CivilStatusId, CivilStatusName,
                                     CreateBy, CreationDate, ModifiedBy, ModifiedDate)
            OUTPUT inserted.CivilStatusId, inserted.CivilStatusName,
                   inserted.CreateBy, inserted.CreationDate,
                   inserted.ModifiedBy, inserted.ModifiedDate
            VALUES (@CivilStatusId, @CivilStatusName,
                    @CreateBy, @CreationDate, @ModifiedBy, @ModifiedDate);
        END TRY
        BEGIN CATCH
            DECLARE @ERRORNUMBER INT, @MESSAGE NVARCHAR(4000), @XACT_STATE INT;
    
            SELECT 
                @ERRORNUMBER = ERROR_NUMBER(), 
                @MESSAGE = ERROR_MESSAGE(), 
                @XACT_STATE = XACT_STATE();
    
            RAISERROR(@MESSAGE, 16, 1);
        END CATCH
    END
    

    这是我的代码,我在那里尝试接球,

    public async Task<BaseResponse<CivilStatusResponseDto>> Handle(CreateCivilStatusCommand request, CancellationToken cancellationToken)
    {
        BaseResponse<CivilStatusResponseDto> response = new BaseResponse<CivilStatusResponseDto>();
    
        try
        {
            CivilStatus civilStatus = await _civilStatusRepository.SaveCivilStatus(_mapper.Map<CivilStatus>(request));
    
            response.IsSuccess = true;
            response.Data = _mapper.Map<CivilStatusResponseDto>(civilStatus);
            response.Message = GlobalMessages.MESSAGE_SAVE;
        }
        catch (Exception ex)
        {
            if (ex.Source is not null && ex.Source.Contains("SqlClient"))
            {
                response.IsSuccess = false;
                response.Message = ex.Message;
            }
            else
            {
                response.IsSuccess = false;
                response.Message = GlobalMessages.MESSAGE_EXCEPTION;
                WatchLogger.Log(ex.Message);
            }
        }
    
        return response;
    }
    

    这是一张 SqlException 已经抛出:

    enter image description here

    当我放置断点时:

    enter image description here

    我尽了最大的努力去访问这些房产,但我做不到。

    我很感激你的帮助

    0 回复  |  直到 1 年前
        1
  •  0
  •   Charlieface    1 年前

    你的主要问题是你抓到了错误的类型。 你需要抓住 Microsoft.Data.SqlClient.SqlException 而不是 System.Data.SqlClient.SqlException

    此外,您的过程的错误处理还有很多不足之处:

    • 使用 THROW 而不是 RAISERROR
    • 设置 XACT_ABORT 将来 ON 以便更好地处理错误。错误将强制立即终止批处理或过程。
    • 移除 BEGIN CATCH 块它没有做任何有用的事情,只会扰乱异常流,并导致某些类型的错误被错误地吞噬或返回。
    • 在整个过程中使用实际事务,以确保一致性。
      • 因此,这需要 UPDLOCK 上的锁定提示 SELECT 查询
    • 而不是更改为 UPPER 使用 COLLATE someCaseInsensitiveCollationHere 。甚至更好:更改列的实际排序规则。
    CREATE PROCEDURE CivilStatusSave
         @CivilStatusId CHAR(1), 
         @CivilStatusName NVARCHAR(15),
         @CreateBy NVARCHAR(60),
         @CreationDate DATETIME,
         @ModifiedBy NVARCHAR(60),
         @ModifiedDate DATETIME
    AS
    
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    SET NOCOUNT, XACT_ABORT ON;
    
    BEGIN TRAN;
    
    IF EXISTS (SELECT 1
        FROM CivilStates AS cs WITH (UPDLOCK)
        WHERE cs.CivilStatusId = @CivilStatusId)
    BEGIN
        THROW 50001, 'Ya se encuentra un registro en el sistema, con este codigo', 1;
    END;
            
    IF EXISTS (SELECT 1
        FROM CivilStates AS cs WITH (UPDLOCK)
        WHERE cs.CivilStatusName = @CivilStatusName COLLATE Latin1_General_100_CI_AI
    BEGIN
        THROW 50002, 'Ya se encuentra un registro en el sistema, con este estado civil', 2;
    END;
    
    INSERT INTO CivilStates
        (CivilStatusId, CivilStatusName, CreateBy,
         CreationDate, ModifiedBy, ModifiedDate)
    OUTPUT inserted.CivilStatusId, inserted.CivilStatusName,
           inserted.CreateBy, inserted.CreationDate,
           inserted.ModifiedBy, inserted.ModifiedDate
    VALUES (@CivilStatusId, @CivilStatusName, @CreateBy,
            @CreationDate, @ModifiedBy, @ModifiedDate);
    
    COMMIT;
    

    老实说,理论上,您可以仅依靠唯一/主键来强制执行条件,尽管错误消息不太容易理解。