2009-06-29 37 views
25

Tôi có một quy trình được lưu trữ thực hiện một số xác thực tham số và sẽ không thành công và ngừng thực thi nếu tham số không hợp lệ.Cách "đúng" để thực hiện xác thực thông số thủ tục lưu trữ

tiếp cận đầu tiên của tôi cho kiểm tra lỗi trông như thế này:

create proc spBaz 
(
    @fooInt int = 0, 
    @fooString varchar(10) = null, 
    @barInt int = 0, 
    @barString varchar(10) = null 
) 
as 
begin 
    if (@fooInt = 0 and (@fooString is null or @fooString = '')) 
    raiserror('invalid parameter: foo', 18, 0) 

    if (@barInt = 0 and (@barString is null or @barString = '')) 
    raiserror('invalid parameter: bar', 18, 0) 

    print 'validation succeeded' 
    -- do some work 
end 

này không làm các trick kể từ mức độ nghiêm trọng 18 không chỉ dừng lại việc thực hiện và 'xác nhận thành công' được in cùng với các thông báo lỗi.

Tôi biết tôi chỉ đơn giản là có thể thêm một trở lại sau mỗi RAISERROR nhưng điều này có vẻ loại xấu xí với tôi:

if (@fooInt = 0 and (@fooString is null or @fooString = '')) 
    begin 
    raiserror('invalid parameter: foo', 18, 0) 
    return 
    end 

    ... 

    print 'validation succeeded' 
    -- do some work 

Kể từ lỗi với mức độ nghiêm trọng 11 trở lên đang bắt trong một khối try/catch cách tiếp cận khác Tôi đã thử nghiệm là để đóng gói lỗi của tôi kiểm tra bên trong một khối try/catch như vậy. Vấn đề là lỗi đã bị nuốt và không được gửi cho khách hàng chút nào. Vì vậy, tôi đã làm một số nghiên cứu và tìm ra cách để rethrow lỗi:

tôi vẫn không hài lòng với phương pháp này vì vậy tôi hỏi bạn:

Làm thế nào để xác nhận thông số của bạn trông như thế nào? Có một số loại "thực hành tốt nhất" để làm loại kiểm tra?

Trả lời

37

Tôi không nghĩ rằng có một cách "đúng" duy nhất để thực hiện việc này.

Tùy chọn của riêng tôi sẽ tương tự như ví dụ thứ hai của bạn, nhưng với bước xác thực riêng cho từng thông số và thông báo lỗi rõ ràng hơn.

Như bạn nói, đó là một chút cồng kềnh và xấu xí, nhưng mục đích của mã là hiển nhiên đối với bất kỳ ai đọc nó, và nó được hoàn thành công việc.

IF (ISNULL(@fooInt, 0) = 0) 
BEGIN 
    RAISERROR('Invalid parameter: @fooInt cannot be NULL or zero', 18, 0) 
    RETURN 
END 

IF (ISNULL(@fooString, '') = '') 
BEGIN 
    RAISERROR('Invalid parameter: @fooString cannot be NULL or empty', 18, 0) 
    RETURN 
END 
+0

Có lý do nào khiến bạn sử dụng IF (ISNULL (@fooString, '') = '') thay vì IF (@fooString là null) không? – macleojw

+9

@macleojw: Anh ta kiểm tra null và '' cùng một lúc .. thông minh :) – VVS

+6

Trình xác thực thứ hai có cú pháp không hợp lệ: 'RAISEERROR'. Chỉ nên có một 'e'. Hài hước là bằng tiếng Anh nó là chính xác như 'nâng cao + lỗi' đã tăng gấp đôi 'e' nhưng không phải trong ngôn ngữ MS SQL. –

1

Chúng tôi thường tránh raiseerror() và trả về một giá trị cho biết một lỗi, ví dụ như một số âm:

if <errorcondition> 
    return -1 

Hoặc vượt qua kết quả trong hai ra các thông số:

create procedure dbo.TestProc 
    .... 
    @result int output, 
    @errormessage varchar(256) output 
as 
set @result = -99 
set @errormessage = null 
.... 
if <errorcondition> 
    begin 
    set @result = -1 
    set @errormessage = 'Condition failed' 
    return @result 
    end 
+0

Tại sao bạn thích trả lại hơn raiseerror()? – macleojw

+0

Raiseerror là không thể đoán trước (có thể tiếp tục thực hiện!) Và không giao dịch khách hàng eveyr với nó trong cùng một cách. Một khách hàng perl có thể chết! – Andomar

0

Tôi muốn quay trở lại càng sớm càng tốt và không thấy mọi thứ trở lại từ cùng một điểm ở cuối quy trình. Tôi đã chọn thói quen này để lắp ráp, cách đây nhiều năm. Ngoài ra, tôi luôn trả lại giá trị:

RETURN 10 

Ứng dụng sẽ hiển thị lỗi nghiêm trọng về số dương và sẽ hiển thị thông báo cảnh báo người dùng về giá trị âm.

Chúng tôi luôn trả lại thông số OUTPUT với văn bản của thông báo lỗi.

dụ:

IF ~error~ 
BEGIN 
    --if it is possible to be within a transaction, so any error logging is not ROLLBACK later 
    IF XACT_STATE()!=0 
    BEGIN 
     ROLLBACK 
    END 

    SET @OutputErrMsg='your message here!!' 
    INSERT INTO ErrorLog (....) VALUES (.... @OutputErrMsg) 
    RETURN 10 

END 
+0

Tôi muốn sử dụng sproc trong một sproc khác và muốn kiểm tra lỗi ít nhất có thể để tăng lỗi và bắt nó ở sproc ngoài có vẻ là cách tốt nhất để làm điều đó. – VVS

+1

một ngày nào đó khi thủ tục này được gọi từ một vị trí khác, tôi hy vọng họ cũng nhớ bắt lỗi. Tôi nghĩ tốt nhất là nên nắm bắt tất cả các lỗi khi chúng xảy ra, xử lý chúng cục bộ và trả lại thông tin thích hợp. –

1

Như bạn có thể nhìn thấy từ lịch sử câu trả lời này tôi theo câu hỏi này và câu trả lời được chấp nhận, và sau đó tiếp tục 'phát minh' một giải pháp đó là cơ bản giống như cách tiếp cận thứ hai của bạn.

Caffeine là nguồn năng lượng chính của tôi, do thực tế là tôi dành phần lớn thời gian của mình vào nửa đêm khi tôi dành quá nhiều thời gian để viết mã; vì vậy tôi đã không nhận ra giả mạo của tôi cho đến khi bạn chỉ ra nó đúng. Vì vậy, đối với hồ sơ, tôi thích cách tiếp cận thứ hai của bạn: sử dụng SP để tăng lỗi hiện tại và sau đó sử dụng TRY/CATCH xung quanh xác thực thông số của bạn.

Nó làm giảm nhu cầu cho tất cả các khối IF/BEGIN/END và do đó làm giảm số lượng dòng cũng như đặt trọng tâm trở lại vào xác thực. Khi đọc qua mã cho SP, điều quan trọng là có thể thấy các bài kiểm tra được thực hiện trên các tham số; tất cả các fluff cú pháp bổ sung để đáp ứng các phân tích cú pháp SQL chỉ được trong cách, theo ý kiến ​​của tôi.

+0

Có lý do nào khiến bạn sao chép phương pháp thứ hai của tôi và thậm chí là tái tạo lại SP-ban đầu mà tôi đã sử dụng không? – VVS

+0

@VVS - oh bạn đã đúng! Nó không cố ý, tôi đọc qua câu hỏi và qua câu trả lời. Sau đó, do thiếu ngủ tôi nhanh chóng quên toàn bộ gam màu tùy chọn được hiển thị ở đây và ban đầu đi cho kết quả if/begin/end rồi 'khám phá' phương pháp này - quên rằng đây là một trong các tùy chọn bạn đã thử. Xin lỗi! –

0

Tôi luôn sử dụng tham số @Is_Success bit như OUTPUT. Vì vậy, nếu tôi có lỗi thì @ Is_success = 0. Khi thủ tục cha mẹ kiểm tra rằng @ Is_Success = 0 thì nó sẽ quay trở lại giao dịch của nó (với các giao dịch con) và gửi thông báo lỗi từ @Error_Message đến máy khách.

+1

Hm, chỉ có ý nghĩa, nếu giá trị trả về của SP được sử dụng khác. Hoặc là có một lý do chính đáng tại sao không chỉ làm "RETURN x"? – VVS

+0

Bạn luôn có hai khả năng xảy ra lỗi: lỗi SQL (ví dụ: phân tích cú pháp XML) và logic (ví dụ: lỗi ràng buộc). Nếu bạn không tạo sự khác biệt giữa chúng, bạn sẽ mất quyền kiểm soát hành vi ứng dụng. Nếu bạn đăng nhập lỗi bên ngoài SQL, ví dụ như trong hệ thống tập tin, sau đó ứng dụng của bạn sẽ nhận được loại lỗi. – Dalex

Các vấn đề liên quan