Thực hành tốt nhất để truy vấn dữ liệu từ MS SQL Server trong C #?


9

Cách tốt nhất để truy vấn dữ liệu từ MS SQL Server trong C # là gì?

Tôi biết rằng việc truy vấn SQL trong mã là không thực tế.

Là cách tốt nhất để tạo một thủ tục được lưu trữ và gọi nó từ C # với các tham số?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}

8
"Tôi biết rằng việc có một truy vấn SQL trong mã là không thực tế." - imo, thật vớ vẩn.
GrandmasterB

4
Bạn không phải gọi Conn. Đóng () nếu bạn đã tạo nó trong một khối sử dụng. Toàn bộ điểm của khối sử dụng là bắt chước kiểu dọn dẹp C ++. Một thanh lịch làm sạch từ một thời đại văn minh hơn. Không phải là ngẫu nhiên hay vụng về như phong cách thử.
Lord Tydus

2
FYI. Thủ tục lưu trữ cũng là "mã". Toàn bộ quan điểm của các procs được lưu trữ là cho phép trộn mã thủ tục với SQL kiểu dựa trên tập hợp. Vì vậy, bạn sẽ có một truy vấn trong mã bất kể. Đối với các ứng dụng có khối lượng cực lớn đôi khi tốt hơn là phải thực hiện logic bên ngoài cơ sở dữ liệu để cho phép mở rộng theo chiều ngang bằng cách thêm máy chủ. Nếu bạn có thể duy trì một DB duy nhất, nhưng máy chủ đa dạng cho logic thì việc mở rộng trở nên dễ dàng hơn nhiều.
Lord Tydus

@GrandmasterB chúng tôi có một lượng đáng kể SQL nội tuyến trong C # (C # LỘC của chúng tôi hiện đã gần 2 triệu) - và 6 năm sau nó quay lại cắn chúng tôi vì bây giờ chúng tôi cần săn lùng SQL nội tuyến đó (gần đây chúng tôi đã thuê một chuyên gia SQL - vì vậy chúng tôi đang thực hiện các chỉnh sửa hiệu suất). Tin tôi đi: bạn không bao giờ biết ứng dụng của bạn sẽ lớn đến mức nào và mọi thứ sẽ thay đổi như thế nào trong tương lai. Giữ các ngôn ngữ khác nhau trong các tệp khác nhau - ngay cả khi bạn chỉ ủy thác nó cho các tài nguyên hiển thị. Bạn cũng có thể làm // SQLCODEđiều đó - nhưng bạn cần nhớ để làm điều đó.
Jonathan Dickinson

1
@JonathanDickinson, Sử dụng procs được lưu trữ nếu bạn muốn. Tôi đã nói nhiều lần chúng hữu ích khi bạn có các cơ sở mã khác nhau hoạt động trên cùng một cơ sở dữ liệu. Nhưng chỉ vì chúng hữu ích trong một số trường hợp không tự động khiến chúng không sử dụng chúng 'thực hành xấu' mọi lúc . Nếu việc sử dụng các câu lệnh SQL trực tiếp không gây ra vấn đề, thì đó không phải là "thực tiễn xấu" cho ứng dụng đó.
GrandmasterB

Câu trả lời:


10

Sử dụng các thủ tục được lưu trữ là một cách, và đã được sử dụng rộng rãi trong nhiều năm.

Một cách hiện đại hơn để tương tác với cơ sở dữ liệu SQL Server từ C # (hoặc bất kỳ ngôn ngữ .NET nào) là sử dụng Entity Framework. Ưu điểm của Entity Framework là nó cung cấp mức độ trừu tượng cao hơn.

Để trích dẫn từ Microsoft ( https://msdn.microsoft.com/en-us/data/jj590134 ):

Khung thực thể ADO.NET cho phép các nhà phát triển tạo các ứng dụng truy cập dữ liệu bằng cách lập trình theo mô hình ứng dụng khái niệm thay vì lập trình trực tiếp với lược đồ lưu trữ quan hệ. Mục tiêu là giảm số lượng mã và bảo trì cần thiết cho các ứng dụng hướng dữ liệu. Các ứng dụng Entity Framework cung cấp các lợi ích sau:

  • Các ứng dụng có thể hoạt động theo mô hình khái niệm tập trung vào ứng dụng hơn, bao gồm các loại có tính kế thừa, các thành viên phức tạp và các mối quan hệ.
  • Các ứng dụng được giải phóng khỏi các phụ thuộc được mã hóa cứng trên một công cụ dữ liệu hoặc lược đồ lưu trữ cụ thể.
  • Các ánh xạ giữa mô hình khái niệm và lược đồ lưu trữ cụ thể có thể thay đổi mà không thay đổi mã ứng dụng.
  • Các nhà phát triển có thể làm việc với một mô hình đối tượng ứng dụng nhất quán có thể được ánh xạ tới các lược đồ lưu trữ khác nhau, có thể được triển khai trong các hệ thống quản lý cơ sở dữ liệu khác nhau.
  • Nhiều mô hình khái niệm có thể được ánh xạ tới một lược đồ lưu trữ duy nhất.
  • Hỗ trợ truy vấn tích hợp ngôn ngữ (LINQ) cung cấp xác thực cú pháp thời gian biên dịch cho các truy vấn theo mô hình khái niệm.

Việc sử dụng ORM so với các thủ tục được lưu trữ liên quan đến sự đánh đổi, đặc biệt là về mặt bảo mật và nơi logic tồn tại.

Cách tiếp cận "cổ điển" để phát triển với SQL Server là để logic ứng dụng nằm trong các thủ tục và chương trình được lưu trữ chỉ được trao quyền bảo mật để thực thi các thủ tục được lưu trữ, chứ không phải cập nhật bảng trực tiếp. Khái niệm ở đây là các thủ tục được lưu trữ là lớp logic nghiệp vụ cho (các) ứng dụng. Trong khi lý thuyết là âm thanh, nó có xu hướng không được ủng hộ vì nhiều lý do, được thay thế bằng cách thực hiện logic kinh doanh trong một ngôn ngữ lập trình như C # hoặc VB. Các ứng dụng tốt vẫn được triển khai theo cách tiếp cận theo từng cấp, bao gồm tách các mối quan tâm, v.v. nhưng có nhiều khả năng đi theo một mô hình như MVC.

Một nhược điểm của việc triển khai logic trong ORM thay vì cơ sở dữ liệu là dễ gỡ lỗi và kiểm tra các quy tắc toàn vẹn dữ liệu của những người chịu trách nhiệm về cơ sở dữ liệu (DA hoặc DBA). Lấy ví dụ kinh điển về việc chuyển tiền từ séc của bạn sang tài khoản tiết kiệm, điều quan trọng là việc này phải được thực hiện như một đơn vị công việc nguyên tử, nói cách khác là kẹp trong một giao dịch. Nếu loại chuyển nhượng này chỉ được phép thực hiện thông qua một thủ tục được lưu trữ, thì DA và kiểm toán viên tương đối dễ dàng đối với QA thủ tục được lưu trữ.

Mặt khác, nếu điều này được thực hiện thông qua ORM như Entity Framework và trong sản xuất, người ta phát hiện ra rằng trong những trường hợp hiếm hoi, tiền được lấy từ việc kiểm tra nhưng không được đưa vào gỡ lỗi tiết kiệm có thể phức tạp hơn nhiều, đặc biệt là nếu có nhiều chương trình có liên quan. Đây rất có thể là một trường hợp cạnh, có lẽ liên quan đến các vấn đề phần cứng đặc biệt cần phải xảy ra theo một trình tự cụ thể, vv Làm thế nào để kiểm tra điều này?


Hoặc ORM khác. Có rất nhiều trong số chúng, với những lợi thế và bất lợi khác nhau khi so sánh với EF.
Svick

8
Danh sách nhược điểm của ORM sẽ làm cho câu trả lời này hữu ích hơn.
Den

6

Trên thực tế, khẳng định cơ bản còn gây tranh cãi - có sự đánh đổi giữa cách có SQL trong mã hoặc có mã trong cơ sở dữ liệu (nơi bạn đang hướng tới các thủ tục được lưu trữ).

Kết quả cuối cùng là không có "tốt nhất" duy nhất, đây không phải là điều bạn có thể khái quát bởi vì bất cứ cách nào bạn đi đều đang thỏa hiệp (bạn có được lợi ích nhưng cũng đưa ra các ràng buộc).

Nếu có một sự tương ứng 1-1 giữa ứng dụng của bạn và cơ sở dữ liệu của bạn thì điều đó không thực sự quan trọng. Mặt khác, nếu bạn có một cơ sở dữ liệu lõi lớn được chia sẻ bởi một số lượng đáng kể các ứng dụng thực thi tính nhất quán trong cơ sở dữ liệu giữa các ứng dụng đó trở nên quan trọng hơn nhiều.

Điều quan trọng hơn là lo lắng về kiến ​​trúc và phân lớp ứng dụng của bạn - được cung cấp một lớp truy cập dữ liệu phù hợp cho dù sử dụng ORM như Entity Framework hay NHibernate hoặc làm gì đó trực tiếp hơn nên cách ly hầu hết ứng dụng của bạn khỏi quyết định này bất kể bạn có xây dựng truy vấn không hoặc sử dụng các thủ tục được lưu trữ.


Tôi sẽ tự do tôi có xu hướng làm việc trong các dự án tương đối nhỏ với các nhóm nhỏ (1-3 dev) - sử dụng các thủ tục được lưu trữ, đối với tôi, rắc rối hơn giá trị của nó vì tính chất ứng dụng của chúng tôi (và bộ kỹ năng của tôi?) Triển khai mới mã nói chung dễ hơn nhiều so với cập nhật lược đồ (thậm chí cho phép tôi có mã giúp cập nhật lược đồ tương đối đơn giản) và tôi có thể thực thi các quy tắc kinh doanh bằng cách sử dụng mã truy cập dữ liệu chung. Đây rõ ràng là một ví dụ kinh điển của "Your Mileage May Vary".


2
+1 cho "không có gì tốt nhất", -1 để triển khai mã dễ dàng hơn so với triển khai các thay đổi của Proc được lưu trữ, +1 để chọn cách tiếp cận hợp lý cho ứng dụng của bạn và đảm bảo cách ly DAL - Vì vậy +1.
Joel Brown

Tôi đã đủ điều kiện triển khai bit với "cho tôi" bởi vì điều đó đối với tôi luôn luôn như vậy (đặc biệt là đối với các ứng dụng web) - đối với tất cả những gì nó có thể chịu một chút viết lại trong khu vực đó.
Murph

+1, những gì tốt nhất phụ thuộc vào ứng dụng và tình huống.
GrandmasterB

1
Tôi đoán nó phụ thuộc vào các điều kiện bạn làm việc. Nếu bạn không có các DBA khóa bạn khỏi sản xuất, việc bỏ một Proc thay thế được lưu trữ vào cơ sở dữ liệu có thể dễ dàng đến đáng sợ. Đối với vấn đề đó, không có kiểm soát sản xuất bỏ đánh dấu mới, tập lệnh và thậm chí mã được biên dịch mới vào một ứng dụng tập trung cũng có thể quá dễ dàng.
Joel Brown

@JoelBrown - Chính xác - Tôi cho rằng, không, tôi chắc chắn rằng tôi đã thực hiện một loạt các giả định ở đó. Đầu tiên, lược đồ của tôi được kiểm soát phiên bản (theo kiểu thô sơ nhưng hiệu quả), tôi không phải là dba nhưng tôi đủ thông minh để biết rằng lược đồ của một người cần phải nhất quán. Tôi làm việc chủ yếu trên các ứng dụng web và bạn không thể truy cập cơ sở dữ liệu trừ khi truy cập máy chủ, trong khi tôi đã (chỉ) giảm việc triển khai ứng dụng xuống (ít nhiều) một nút bấm ... tích hợp các cập nhật lược đồ vào triển khai có trong danh sách, nhưng tôi luôn thấy các cập nhật lược đồ căng thẳng hơn so với cập nhật mã (có dễ khôi phục không?)
Murph

4

Miễn là bạn đã tham số hóa các đầu vào của mình thì mọi cách tiếp cận đều hợp lệ. Phần lớn không có truy vấn trong các đối số mã xuất phát từ thời xa xưa khi nhiều thư viện buộc bạn phải nối các câu lệnh của bạn lại với nhau và đó là nơi mà các cuộc tấn công tiêm chích sql xuất phát.


1
Là đủ tham số? Bạn không cần phải vệ sinh là tốt?
StuperUser

điều đó phụ thuộc vào nguồn của bạn và mục đích của bạn. Tôi đã lấy câu hỏi của anh ấy theo nghĩa đen, anh ấy chỉ đọc với một số thông số. trong các trường hợp phổ biến, điều tồi tệ nhất bạn sẽ làm với đầu vào bẩn nếu tham số chính xác là có ngoại lệ loại hoặc không có kết quả với đầu vào xấu. Chèn là khác nhau và thường cần xác nhận trừ khi bạn coi nguồn là có thẩm quyền.
Hóa đơn

0

Thực hành tốt nhất thực sự bị che khuất ở đây - có rất nhiều cách tốt để làm điều đó và cách bạn chọn thực sự nên phụ thuộc vào ứng dụng của bạn là gì và bạn cần làm gì. Điều đó nói rằng, chỉ có hai điều bạn có thể làm thực sự sai:

  • Như @Bill chỉ ra, bạn phải luôn tham số hóa các truy vấn của mình. Xây dựng chuỗi là một vectơ dễ dàng để tiêm SQL cũng như tất cả các cách khó theo dõi lỗi. Nhiều người thông minh hơn đã tìm ra cách để tupelize và thoát sql để bạn không cần phải tự mình tìm ra.

  • Đóng kết nối của bạn. Cách tốt nhất là bọc mọi thứ bằng cách sử dụng câu lệnh, nhưng thử / bắt / cuối cùng cũng tuyệt nếu điều đó làm nổi thuyền của bạn. Nhưng luôn luôn đảm bảo bạn sử dụng kết nối như một chiếc xe giá rẻ - lái nó thật mạnh và nhanh và thoát khỏi nó nhanh chóng.

Một thực tế khác tôi sẽ tranh luận kịch liệt là bạn nên đảm bảo tập trung mã truy cập dữ liệu của mình ở càng ít nơi càng tốt. Chúng tôi không cho phép các ứng dụng web mặt trước giữ tham chiếu trực tiếp đến System.Data.SqlClient để giúp thực thi cảnh báo này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.