2011-09-13 6 views
13

Thông thường tôi phải chèn một số dữ liệu trong một DB và nó không thể được chèn bởi vì bảng có các ràng buộc ngăn cản tôi làm điều đó. Với ứng dụng tôi đang phát triển, một số quy tắc kinh doanh (như "không có hai người có cùng loại id và số" hoặc "sản phẩm XXXX đã được đăng ký") được thực thi bằng các phím UNIQUE hoặc composite và các cơ chế khác. Mặc dù tôi biết rằng DBMS ném một thông báo lỗi (như ORA-6346 hoặc) Tôi không biết làm thế nào để bắt những lỗi trong .net 4.0 và dịch chúng thành một lỗi có thể có ý nghĩa cho lớp kinh doanh.Cách bắt lỗi DB và dịch chúng thành thông tin có ý nghĩa cho lớp doanh nghiệp?

Ví dụ: Tôi đã nhìn thấy cơ chế chèn yêu cầu DB nếu sổ đăng ký đã tồn tại và sau đó nó tiến hành chèn dữ liệu nếu không phải như vậy. Tôi muốn làm điều này chỉ bằng cách sử dụng một truy vấn và bắt lỗi vi phạm cơ sở dữ liệu ràng buộc bởi vì cách đầu tiên dường như với tôi là rất kém hiệu quả (DB có thể cảnh báo bạn về trùng lặp với một lỗi).

Tôi có thể triển khai một cái gì đó như thế?

Lưu ý: Tôi nghĩ rằng có thể bắt ngoại lệ từ cơ sở dữ liệu và sử dụng mã ORA-xxxx của nó để cố gắng tìm ra những gì đã xảy ra. Tôi không nhớ chính xác nếu thông báo lỗi cho thấy ràng buộc nào (tên của ...) đã bị hỏng, nhưng mã lớp nghiệp vụ có thể chứa các hằng số với các tên ràng buộc và, từ chúng, biết điều gì đã xảy ra.

+1

Điều này nghe có vẻ giống như gọi phương thức với try/catch thay vì xác thực đối số trước khi gọi – driushkin

+0

nếu bạn không muốn kiểm tra xem đăng ký đã tồn tại chưa, trước tiên bạn có thể thử tạo và sau đó nếu ngoại lệ được ném từ db, bạn có thể kiểm tra xem RegisterExists() có trả về true hay không, để chắc chắn rằng đó là nguồn gốc của vấn đề, và không phải là db không làm việc gì cả. Nếu đã tồn tại trường hợp là khá hiếm, bạn sẽ không nhận được rằng hiệu suất hit thường xuyên như vậy. –

Trả lời

7

Điều bạn nên làm ở đây phụ thuộc rất nhiều vào kiến ​​trúc hệ thống của bạn và thái độ của bạn đối với việc sắp xếp logic nghiệp vụ.

Nhiều hệ thống kiến ​​trúc sư thích sử dụng cơ sở dữ liệu dưới dạng kho dữ liệu câm và triển khai loại xử lý lỗi và kiểm tra tính toàn vẹn mà bạn đang nói đến ở lớp giữa/ứng dụng. Đây là một cách tiếp cận hoàn toàn hợp lệ, và đặc biệt phù hợp với các hệ thống yêu cầu các bản phát hành nhỏ hơn, nơi mà logic nghiệp vụ có thể thay đổi thường xuyên (dễ dàng hơn để phân phối lại một tuần giữa thực thi hơn là phối hợp phát hành cơ sở dữ liệu) và dữ liệu mô hình khá đơn giản.

Cách tiếp cận khác là đặt một số logic kinh doanh bán cố định được xác định rõ ràng vào lớp cơ sở dữ liệu. Điều này đặc biệt mạnh mẽ khi mô hình dữ liệu phức tạp hơn và bạn có một DBA tốt!;)

Ý kiến ​​cá nhân của tôi là cơ sở dữ liệu doanh nghiệp phải chịu trách nhiệm về tính toàn vẹn của riêng mình và vì vậy tôi thích có logic trong lớp cơ sở dữ liệu để đảm bảo điều này. . Vì vậy, trong ví dụ cụ thể của bạn, tôi chắc chắn sẽ nắm bắt được lỗi và báo cáo có ý nghĩa với lớp ứng dụng của bạn.

Oracle hỗ trợ bắt các loại lỗi khác nhau bằng cách sử dụng các ngoại lệ tên, cho phép bạn tăng các ngoại lệ này lên ứng dụng của mình một cách có ý nghĩa. Ví dụ:

PROCEDURE test() AS 
    b VARCHAR2; 
BEGIN 

    -- if the following row exists, then DUP_VAL_ON_INDEX will be thrown 
    -- (assuming there is a primary key constraint)   

    INSERT INTO table(a,b,c) 
    VALUES(1,2,3); 

    -- if there is no matching record, NO_DATA_FOUND will be thrown 

    SELECT a 
    INTO b 
    FROM TABLE 
    WHERE c = 'blah'; 

EXCEPTION -- both types of exception can be caught and embellished 
    WHEN DUP_VAL_ON_INDEX THEN 
    raise_application_error(-20570, 'Attempted to insert a duplicate value', TRUE); 
    WHEN NO_DATA_FOUND THEN 
    raise_application_error(-20571, 'No matching row in table for value:' || 'blah', TRUE); 
    WHEN OTHERS THEN 
    rollback 
END test; 

Bạn có thể tìm thêm thông tin ở đây: http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/errors.htm

Hope this helps ..

+0

Ý tưởng của bạn là nhiều hơn hoặc ít hơn @mootinator đề xuất? ... Tôi không biết ai cho kiểm tra ...! cả hai đều nói các giải pháp âm thanh ...: S – JPCF

+0

Khi nghi ngờ, hãy đi với ý kiến ​​phổ biến;) –

0

Phương pháp tôi biết và đã sử dụng là tự thực hiện các xác thực giống nhau và trả lại mã lỗi hữu ích cho ứng dụng của bạn. Vì vậy, ví dụ, nếu bạn có một thủ tục lưu trữ mà chèn một bản ghi vào cơ sở dữ liệu, nó cũng nên kiểm tra xem những hạn chế tất cả sẽ được thỏa mãn, và nếu không, trả lại một mã lỗi thích hợp:

(pseudo-sql) 
function create-user 
    @username, @password, @name, @email 
as 

if @username already exists return 1 --duplicate username 
if @email already exists return 2 --duplicate email 

insert user values (@username, @password, @name, @email) 
return 0 -- success 
+2

nếu chúng ta đang nói về oracle trước tiên chúng ta có thể thử chèn và chỉ khi nó không thực hiện các truy vấn bổ sung để tìm ra nguồn của các lỗi thực tế, nó sẽ có hiệu suất cao hơn luôn luôn thực hiện một vài lựa chọn trước khi chèn –

3

Có một cặp vợ chồng các phương pháp tiếp cận, đây là những gì tôi sẽ làm:

  1. Để lỗi phát sinh từ cuộc gọi DB trở lại mã được quản lý của bạn.
  2. Sử dụng thành phần để kiểm tra thông báo lỗi do SQL cung cấp và xác định thông báo "thân thiện với người dùng/lớp thân thiện" tương ứng.

Tôi đồng ý với Mellamokb rằng việc xử lý lỗi có thể được thực hiện trong proc được lưu trữ nhưng điều đó không hoàn toàn phù hợp với kịch bản của bạn khi bạn đặc biệt muốn cung cấp thứ gì đó mà tầng nghiệp vụ hiểu được - theo định nghĩa lớp dữ liệu không bao giờ biết.

Đối với # 2, Thư viện doanh nghiệp MS có một khối xử lý lỗi (tôi nghĩ) cho phép bạn sắp xếp điều đó thông qua cấu hình; hoặc nếu không nó có thể khiến bạn gần gũi.

1

Tôi đã suy nghĩ về điều tương tự gần đây. Tôi đã thực hiện một phương thức mở rộng lấy Message từ một số SqlException và chuyển nó thành một cái gì đó hữu ích hơn cho người dùng cuối bằng cách sử dụng các biểu thức chính quy để trích xuất thông tin hữu ích từ thông báo lỗi và String.Format để đưa thông tin đó vào thư mới.

Tôi đã sử dụng từ điển thứ hai để tìm kiếm các tên ràng buộc được tìm thấy bởi cụm từ thông dụng và dịch những từ đó sang mô tả bằng tiếng Anh về ràng buộc vi phạm.

SQL này thông báo lỗi:

Violation of UNIQUE KEY constraint 'uniq_ticket'. Cannot insert duplicate key in object 'dbo.TicketHeader'. The statement has been terminated.

Returns kết quả này:

Save to table dbo.TicketHeader failed: Ticket number must be unique.

tôi sẽ tưởng tượng nó có thể làm việc rất tương tự cho trường hợp ngoại lệ gửi bởi Oracle.

public static class SqlExceptionExtension 
    { 
     private static readonly Dictionary<string, string> Messages; 
     private static readonly Dictionary<string, string> Constraints; 
     static SqlExceptionExtension() 
     { 
      Messages = new Dictionary<string, string> {{@"Violation of UNIQUE KEY constraint '(?<Constraint>.*)'. Cannot insert duplicate key in object '(.*)'. The statement has been terminated.", "Save to table {2} failed: {0}"}}; 
      Constraints = new Dictionary<string, string> { { "uniq_ticket", "Ticket number must be unique." } }; 
     } 
     public static string BusinessLayerMessage(this Exception e) 
     { 
      foreach(var reg in Messages.Keys) 
      { 
       var match = Regex.Match(e.Message, reg); 
       if (match.Success) 
       { 
        string friendlyConstraint = ""; 
        if (match.Groups["Constraint"] != null) 
        { 
         friendlyConstraint = Constraints[match.Groups["Constraint"].Value] ?? 
              match.Groups["Constraint"].Value; 
        } 
        var groups = match.Groups.Cast<Group>().Select(x => x.Value); 
        var strings = new [] {friendlyConstraint}; 
        return String.Format(Messages[reg], strings.Concat(groups).ToArray()); 
       } 
      } 
      return "Unexpected Database error."; 
     } 
    } 
} 

Tôi muốn tưởng tượng bạn có thể làm điều này trên các cá nhân SqlError hoặc OracleError s nằm trong ngoại lệ của bạn cho kết quả đáng tin cậy hơn, đây chỉ là một bằng chứng của khái niệm.

0

Nếu bạn đang tìm kiếm nguồn cảm hứng, hãy xem NHibernate xử lý việc này như thế nào với giao diện ISQLExceptionConverter của nó. Bạn có thể xem triển khai mẫu here.