2013-03-22 39 views
6

Tôi đang gọi thủ tục được lưu trữ chèn dữ liệu vào cơ sở dữ liệu máy chủ sql từ C#. Tôi có một số trở ngại trên bàn như cột, vv độc đáo Hiện nay tôi có đoạn mã sau:cách tốt nhất để bắt các lỗi ràng buộc cơ sở dữ liệu

try 
{ 
    // inset data 
} 
catch (SqlException ex) 
{ 
    if (ex.Message.ToLower().Contains("duplicate key")) 
    { 

     if (ex.Message.ToLower().Contains("url")) 
     { 
      return 1; 
     } 

     if (ex.Message.ToLower().Contains("email")) 
     { 
      return 2; 
     } 
    } 

    return 3; 
} 

Có thực hành tốt hơn để kiểm tra xem cột là vv độc đáo trước khi chèn dữ liệu trong C#, hoặc trong thủ tục lưu trữ hoặc để cho một ngoại lệ xảy ra và xử lý như trên? Tôi không phải là một fan hâm mộ của các bên trên nhưng tìm kiếm thực hành tốt nhất trong lĩnh vực này.

+0

Như một điều này, nếu bạn kiểm tra. Tôi sẽ kiểm tra trên ErrorCode vì điều đó sẽ độc đáo hơn và ít có khả năng thay đổi: http://msdn.microsoft.com/en-us/library/aa258747(v=sql.80).aspx –

Trả lời

6

Tôi xem các ràng buộc về cơ sở dữ liệu như là một loại phương sách cuối cùng. (Nghĩa là tất cả chúng nên có mặt trong lược đồ của bạn như một cách sao lưu duy trì tính toàn vẹn dữ liệu.) Nhưng tôi muốn nói rằng dữ liệu thực sự là hợp lệ trước bạn hãy thử lưu nó vào cơ sở dữ liệu. Nếu không vì lý do nào khác, vì việc cung cấp phản hồi về đầu vào không hợp lệ là mối quan tâm về giao diện người dùng và lỗi hiệu lực dữ liệu thực sự không nên bong bóng lên và xuống toàn bộ ngăn xếp mỗi lần.

Hơn nữa, có nhiều loại xác nhận bạn muốn tạo về hình dạng dữ liệu của bạn không thể diễn tả bằng cách sử dụng các ràng buộc dễ dàng. (Ví dụ: trạng thái chuyển tiếp của một đơn đặt hàng. "Một đơn đặt hàng chỉ có thể đi tới SHIPPED từ PAID" hoặc các tình huống phức tạp hơn.) Đó là, bạn cần phải sử dụng các kiểm tra dựa trên thủ tục dựa trên ngôn ngữ. , và sau đó có báo cáo một số loại mã lỗi là tốt, và bao gồm phức tạp hơn trong ứng dụng của bạn chỉ để làm tất cả các xác nhận dữ liệu của bạn trong định nghĩa lược đồ.

Xác thực khó có thể đặt trong ứng dụng vì nó liên quan đến cả giao diện người dùng được kết hợp với lược đồ mô hình, nhưng tôi quay sang bên cạnh giao diện người dùng.

+1

Tôi đồng ý hoàn toàn. Lỗi ràng buộc cho biết một lỗi trong mã của bạn - mã của bạn cho phép người dùng nhập dữ liệu mà cơ sở dữ liệu từ chối. –

+0

Mã bạn đang làm việc trên mục nhập duy nhất cho dữ liệu tham chiếu ràng buộc? Nếu vậy, sau đó hoàn toàn dựa vào lớp mã của bạn để xác định giá trị nào có thể được lưu trữ. Lý do duy nhất tôi hỏi là vì tôi đã làm việc trên các hệ thống kế thừa, nơi có nhiều điểm vào bảng không nhất thiết được xác định trong một bộ mã hoặc mã khác (xem: các ứng dụng ASP cổ điển nằm ngang) và có ràng buộc kiểm tra có giá trị để đảm bảo rằng codebase cũ không vi phạm tính toàn vẹn tham chiếu hoặc các ràng buộc duy nhất. – antinescience

+0

Hoàn toàn đồng ý - mặc dù các ràng buộc nên ở đó, chỉ để bảo vệ các trường hợp các lớp xác nhận trên không thành công. Tôi đã thực hiện một số thử nghiệm hiệu suất về điều này: http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling và http://www.mssqltips.com/sqlservertip/2632/ kiểm tra-cho-tiềm năng-ràng buộc-vi phạm-trước khi nhập-sql-server-try-và-catch-logic/ –

0

tôi đã làm một cái gì đó như thế này:

public class SqlExceptionHelper 
{ 
    public SqlExceptionHelper(SqlException sqlException) 
    { 
     // Do Nothing. 
    } 

    public static string GetSqlDescription(SqlException sqlException) 
    { 
     switch (sqlException.Number) 
     { 
      case 21: 
       return "Fatal Error Occurred: Error Code 21."; 
      case 53: 
       return "Error in Establishing a Database Connection: 53."; 
      default 
       return ("Unexpected Error: " + sqlException.Message.ToString()); 
     } 
    } 
} 

nào cho phép nó được tái sử dụng, và nó sẽ cho phép bạn để có được những Codes Lỗi từ SQL.

Sau đó chỉ cần thực hiện:

public class SiteHandler : ISiteHandler 
{ 
    public string InsertDataToDatabase(Handler siteInfo) 
    { 
      try 
      { 
       // Open Database Connection, Run Commands, Some additional Checks. 
      } 
      catch(SqlException exception) 
      { 
      SqlExceptionHelper errorCompare = new SqlExceptionHelper(exception); 
      return errorCompare.ToString(); 
      } 
    } 
} 

Sau đó, nó được cung cấp một số lỗi cụ thể cho lần xuất hiện chung. Nhưng như đã đề cập ở trên; bạn thực sự cần đảm bảo rằng bạn đã kiểm tra dữ liệu của mình trước khi bạn chỉ nhập dữ liệu vào cơ sở dữ liệu của mình. Bằng cách đó không có ràng buộc không khớp nào tồn tại hoặc tồn tại.

Hy vọng nó chỉ cho bạn một hướng tốt.

0

Phụ thuộc vào những gì bạn đang cố gắng làm. Một số điều cần suy nghĩ về:

  • Bạn muốn xử lý lỗi của mình ở đâu? Tôi khuyên bạn nên càng gần với dữ liệu càng tốt.
  • Bạn muốn biết thông tin gì về lỗi này? Người dùng của bạn có cần biết rằng 'bạn đã sử dụng ID đó' ...?
  • v.v.

Ngoài ra - những hạn chế có thể được tốt - Tôi không 100% đồng ý với câu trả lời millimoose về thời điểm đó - Ý tôi là, tôi làm trong phải như thế này/hiệu suất tốt hơn lý tưởng - nhưng trên thực tế, nếu bạn không có quyền kiểm soát nhà phát triển/qc của mình và đặc biệt là khi thực thi các quy tắc có thể làm hỏng cơ sở dữ liệu của bạn (hoặc cách khác, hãy phá vỡ các đối tượng phụ thuộc như báo cáo, v.v ... nếu một khóa trùng lặp) ở đâu đó, bạn cần một số rào cản chống lại (ví dụ) mục nhập khóa trùng lặp.

1

Tôi muốn một thủ tục được lưu trữ kiểm tra các vi phạm tiềm ẩn trước khi chỉ cần ném ing dữ liệu tại SQL Server và để cho các ràng buộc bong bóng lên một lỗi. Lý do cho điều này là thực hiện liên quan đến:

http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling

http://www.mssqltips.com/sqlservertip/2632/checking-for-potential-constraint-violations-before-entering-sql-server-try-and-catch-logic/

Một số người sẽ biện hộ rằng trở ngại ở lớp cơ sở dữ liệu là không cần thiết kể từ khi chương trình của bạn có thể làm tất cả mọi thứ. Lý do tôi sẽ không chỉ dựa vào chương trình C# của bạn để phát hiện các bản sao là mọi người sẽ tìm cách ảnh hưởng đến dữ liệu mà không phải trải qua chương trình C# của bạn. Bạn có thể giới thiệu các chương trình khác sau. Bạn có thể có người viết kịch bản của riêng mình hoặc tương tác trực tiếp với cơ sở dữ liệu. Bạn có thực sự muốn rời khỏi bảng không được bảo vệ bởi vì họ không tôn trọng các quy tắc kinh doanh của bạn không? Và tôi không nghĩ rằng chương trình C# chỉ nên ném dữ liệu vào bàn và hy vọng là tốt nhất.

Nếu quy tắc kinh doanh của bạn thay đổi, bạn có thực sự muốn phải biên dịch lại ứng dụng của mình (hoặc tất cả nhiều ứng dụng) không? Tôi đoán điều đó phụ thuộc vào cơ sở dữ liệu của bạn được bảo vệ tốt như thế nào và khả năng thay đổi/thường xuyên quy tắc kinh doanh của bạn.

3

tôi thấy hai câu hỏi ở đây, và ở đây là mất của tôi ...

Are hạn chế cơ sở dữ liệu tốt? Đối với các hệ thống lớn, chúng không thể thực hiện được. Hầu hết các hệ thống lớn có nhiều hơn một giao diện người dùng và không phải lúc nào cũng có các ngôn ngữ tương thích, nơi có thể chia sẻ logic kiểm tra dữ liệu giữa cấp hoặc giao diện người dùng. Chúng cũng có thể có các quy trình lô trong Transact-SQL hoặc chỉ PL/SQL. Nó là tốt để nhân đôi việc kiểm tra trên mặt trước, nhưng trong một ứng dụng đa người dùng cách duy nhất để thực sự kiểm tra tính độc đáo là để chèn các bản ghi và xem những gì cơ sở dữ liệu nói. Cùng với các ràng buộc khóa ngoại - bạn không thực sự biết cho đến khi bạn cố gắng chèn/cập nhật/xóa.

Trường hợp ngoại lệ có được phép ném hoặc trả về giá trị được thay thế không? Dưới đây là mã từ câu hỏi:

try 
    { 
     // inset data 
    } 
    catch (SqlException ex) 
    { 
     if (ex.Message.ToLower().Contains("duplicate key")) 
     { 
      if (ex.Message.ToLower().Contains("url")) 
      { 
       return 1; // Sure, that's one good way to do it 
      } 
      if (ex.Message.ToLower().Contains("email")) 
      { 
       return 2; // Sure, that's one good way to do it 
      } 
     } 
     return 3; // EVIL! Or at least quasi-evil :) 
    } 

Nếu bạn có thể đảm bảo rằng các chương trình gọi điện thoại thực sự sẽ hành động dựa trên các giá trị trả về, tôi nghĩ rằng return 1return 2 được tốt nhất còn lại để phán xét bạn. Tôi thích để rethrow một ngoại lệ tùy chỉnh cho các trường hợp như thế này (ví dụ DuplicateEmailException) nhưng đó chỉ là tôi - giá trị trả lại sẽ làm các trick quá. Sau khi tất cả, các lớp người tiêu dùng có thể bỏ qua các ngoại lệ dễ dàng như họ có thể bỏ qua các giá trị trả về.

Tôi chống lại số return 3. Điều này có nghĩa là có một ngoại lệ không mong muốn (cơ sở dữ liệu bị hỏng, kết nối kém, bất cứ điều gì). Ở đây bạn có lỗi không xác định và thông tin chẩn đoán duy nhất bạn có là: "3". Hãy tưởng tượng đăng một câu hỏi trên SO nói rằng Tôi đã cố gắng chèn một hàng nhưng hệ thống đã nói '3'. Xin cho biết. Nó sẽ bị đóng trong vài giây :)

Nếu bạn không biết cách xử lý ngoại lệ trong lớp dữ liệu, không có cách nào để người tiêu dùng của lớp dữ liệu có thể xử lý nó. Tại thời điểm này bạn đang khá nhiều hosed vì vậy tôi nói đăng nhập lỗi, sau đó thoát ra như gracefully càng tốt với một "Unexpected error" tin nhắn.

Tôi biết tôi đã nói một chút về ngoại lệ không mong muốn, nhưng tôi đã xử lý quá nhiều sự cố hỗ trợ trong trường hợp lập trình viên chỉ sắp xếp lại ngoại lệ cơ sở dữ liệu và khi có điều gì đó bất ngờ xuất hiện ứng dụng không thành công hoặc không thành công. thông tin. Rất nghịch ngợm.

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