Nó có được coi là một mẫu chống viết SQL trong mã nguồn không?


87

Được coi là một mô hình chống mã hóa SQL cứng vào một ứng dụng như thế này:

public List<int> getPersonIDs()
{    
    List<int> listPersonIDs = new List<int>();
    using (SqlConnection connection = new SqlConnection(
        ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
    using (SqlCommand command = new SqlCommand())
    {
        command.CommandText = "select id from Person";
        command.Connection = connection;
        connection.Open();
        SqlDataReader datareader = command.ExecuteReader();
        while (datareader.Read())
        {
            listPersonIDs.Add(Convert.ToInt32(datareader["ID"]));
        }
    }
    return listPersonIDs;
}

Tôi thường có một lớp kho lưu trữ, v.v., nhưng tôi đã loại trừ nó trong đoạn mã trên để đơn giản.

Gần đây tôi đã có một số phản hồi từ một đồng nghiệp đã phàn nàn rằng SQL được viết trong mã nguồn. Tôi đã không có cơ hội để hỏi tại sao và anh ấy đã đi được hai tuần (có thể nhiều hơn). Tôi cho rằng anh ta cũng có nghĩa là:

  1. Sử dụng LINQ
    hoặc
  2. Sử dụng các thủ tục được lưu trữ cho SQL

Tôi có đúng không? Nó có được coi là một mẫu chống viết SQL trong mã nguồn không? Chúng tôi là một nhóm nhỏ làm việc trong dự án này. Lợi ích của các thủ tục được lưu trữ Tôi nghĩ là các Nhà phát triển SQL có thể tham gia vào quá trình phát triển (viết các thủ tục được lưu trữ, v.v.).

Chỉnh sửa Liên kết sau đây nói về các câu lệnh SQL được mã hóa cứng: https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/hard-coding-sql-statements . Có bất kỳ lợi ích của việc chuẩn bị một câu lệnh SQL?


31
"Sử dụng Linq" và "Sử dụng các thủ tục được lưu trữ" không phải là lý do; chúng chỉ là những gợi ý. Đợi hai tuần, và hỏi anh ta cho lý do.
Robert Harvey

47
Mạng Stack Exchange sử dụng một ORM vi mô gọi là Dapper. Tôi nghĩ thật hợp lý khi nói rằng phần lớn mã Dapper là "SQL được mã hóa cứng" (ít nhiều). Vì vậy, nếu đó là một thực tiễn tồi, thì đó là một thực tiễn tồi được áp dụng bởi một trong những ứng dụng web nổi bật nhất trên hành tinh.
Robert Harvey

16
Để trả lời câu hỏi của bạn về các kho lưu trữ, SQL được mã hóa cứng vẫn là SQL được mã hóa cứng bất kể bạn đặt nó ở đâu. Sự khác biệt là kho lưu trữ cung cấp cho bạn một nơi để đóng gói SQL được mã hóa cứng. Đây là một lớp trừu tượng ẩn các chi tiết của SQL khỏi phần còn lại của chương trình.
Robert Harvey

26
Không, SQL trong mã không phải là mẫu chống. Nhưng đó là rất nhiều mã tấm nồi hơi cho một truy vấn SQL đơn giản.
GrandmasterB

45
Có sự khác biệt giữa 'trong mã nguồn' và 'trải đều trên mã nguồn'
tofro

Câu trả lời:


112

Bạn đã loại trừ phần quan trọng cho đơn giản. Các kho lưu trữ là lớp trừu tượng cho sự kiên trì. Chúng tôi tách riêng sự bền bỉ thành lớp riêng để có thể thay đổi công nghệ kiên trì dễ dàng hơn khi chúng tôi cần. Do đó, việc có SQL bên ngoài lớp kiên trì hoàn toàn cho phép nỗ lực có một lớp lưu giữ riêng biệt.

Kết quả là: SQL vẫn ổn trong lớp kiên trì dành riêng cho công nghệ SQL (ví dụ: SQL ổn trong một SQLCustomerRepositorynhưng không phải ở a MongoCustomerRepository). Bên ngoài lớp kiên trì, SQL phá vỡ sự trừu tượng của bạn và do đó được coi là thực tiễn rất xấu (theo tôi).

Đối với các công cụ như LINQ hoặc JPQL: Những công cụ đó chỉ có thể trừu tượng hóa các hương vị của SQL ngoài kia. Việc có các truy vấn LINQ-Code hoặc JPQL bên ngoài kho lưu trữ sẽ phá vỡ sự trừu tượng hóa bền bỉ giống như SQL thô.


Một ưu điểm lớn khác của lớp lưu giữ riêng biệt là nó cho phép bạn hủy mã logic nghiệp vụ của mình mà không phải thiết lập máy chủ DB.

Bạn nhận được cấu hình bộ nhớ thấp, kiểm tra đơn vị nhanh với kết quả có thể lặp lại trên tất cả các nền tảng mà ngôn ngữ của bạn hỗ trợ.

Trong kiến ​​trúc MVC + Service, đây là một nhiệm vụ đơn giản để mô phỏng thể hiện của kho lưu trữ, tạo một số dữ liệu giả trong bộ nhớ và xác định rằng kho lưu trữ sẽ trả về dữ liệu giả đó khi một getter nhất định được gọi. Sau đó, bạn có thể xác định dữ liệu kiểm tra mỗi lần không đáng tin cậy nhất và không phải lo lắng về việc dọn sạch DB sau đó.

Việc kiểm tra ghi vào DB rất đơn giản: xác minh rằng các phương thức cập nhật có liên quan trên lớp kiên trì đã được gọi và khẳng định rằng các thực thể ở trạng thái chính xác khi điều đó xảy ra.


80
Ý tưởng rằng "chúng ta có thể thay đổi công nghệ bền bỉ" là không thực tế và không cần thiết trong phần lớn các dự án trong thế giới thực. SQL / SQL quan hệ là một con thú hoàn toàn khác so với DB NoQuery như MongoDB. Xem bài viết chi tiết về nó. Nhiều nhất, một dự án bắt đầu sử dụng NoQuery cuối cùng sẽ nhận ra lỗi của họ và sau đó chuyển sang RDBMS. Theo kinh nghiệm của tôi, việc cho phép sử dụng trực tiếp Ngôn ngữ truy vấn hướng đối tượng (như JPA-QL) từ mã doanh nghiệp cung cấp kết quả tốt nhất.
Rogério

6
Điều gì xảy ra nếu có rất ít khả năng lớp kiên trì bị thay đổi? Điều gì xảy ra nếu không có ánh xạ một đến một khi thay đổi lớp lưu giữ? Lợi thế của mức độ trừu tượng thêm là gì?
vui mừng

19
@ Rogério Di chuyển từ cửa hàng NoQuery sang RDBMS hoặc ngược lại, như bạn nói có lẽ không thực tế (giả sử lựa chọn công nghệ là phù hợp để bắt đầu). Tuy nhiên, tôi đã tham gia vào một số dự án trong thế giới thực nơi chúng tôi đã di chuyển từ RDBMS này sang RDBMS khác; trong kịch bản đó, một lớp kiên trì đóng gói chắc chắn là một lợi thế.
David

6
"Ý tưởng rằng" chúng ta có thể thay đổi công nghệ bền bỉ "là không thực tế và không cần thiết trong phần lớn các dự án trong thế giới thực." Công ty của tôi trước đây đã viết mã theo giả định đó. Chúng tôi đã phải cấu trúc lại toàn bộ cơ sở mã để hỗ trợ không chỉ một, mà là ba hệ thống lưu trữ / truy vấn hoàn toàn khác nhau và đang xem xét thứ ba và thứ tư. Tệ hơn, ngay cả khi chúng ta chỉ có một cơ sở dữ liệu, việc thiếu hợp nhất đã dẫn đến tất cả các loại tội lỗi mã.
NPSF3000

3
@ Rogério Bạn biết "phần lớn các dự án trong thế giới thực"? Trong công ty của tôi, hầu hết các ứng dụng có thể hoạt động với một trong nhiều DBMS phổ biến và điều này rất hữu ích, vì hầu hết các khách hàng của chúng tôi đều có các yêu cầu không liên quan đến điều đó.
BartoszKP

55

Hầu hết các ứng dụng kinh doanh tiêu chuẩn ngày nay sử dụng các lớp khác nhau với các trách nhiệm khác nhau. Tuy nhiên, lớp bạn sử dụng cho bạn ứng dụng, và đó lớp có mà trách nhiệm là tùy thuộc vào bạn và nhóm của bạn. Trước khi bạn có thể đưa ra quyết định về việc đặt SQL trực tiếp vào hàm bạn đã chỉ cho chúng tôi, bạn cần phải biết

  • Lớp nào trong ứng dụng của bạn có trách nhiệm

  • từ lớp nào chức năng trên là từ

Không có giải pháp "một kích cỡ phù hợp cho tất cả" cho vấn đề này. Trong một số ứng dụng, các nhà thiết kế thích sử dụng khung ORM và để khung tạo ra tất cả SQL. Trong một số ứng dụng, các nhà thiết kế thích lưu trữ SQL như vậy trong các thủ tục được lưu trữ. Đối với một số ứng dụng, có một lớp lưu trữ (hoặc kho lưu trữ) viết tay trong đó SQL tồn tại và đối với các ứng dụng khác, bạn có thể xác định các ngoại lệ trong các trường hợp nhất định từ việc đặt SQL vào lớp kiên trì đó.

Vì vậy, những gì bạn cần suy nghĩ về: lớp nào bạn muốn hoặc cần trong ứng dụng cụ thể của bạn, và bạn muốn có trách nhiệm như thế nào? Bạn đã viết "Tôi thường có một lớp kho lưu trữ" , nhưng trách nhiệm chính xác mà bạn muốn có bên trong lớp đó là gì và bạn muốn đặt trách nhiệm nào ở một nơi khác? Trả lời trước, sau đó bạn có thể tự trả lời câu hỏi của mình.


1
Tôi đã chỉnh sửa câu hỏi. Không chắc chắn nếu nó làm sáng tỏ.
w0051977

18
@ w0051977: liên kết bạn đã đăng không cho chúng tôi biết gì về ứng dụng của bạn , phải không? Có vẻ như bạn đang tìm kiếm một số quy tắc đơn giản, dũng cảm, nơi đặt SQL hoặc không phù hợp với mọi ứng dụng. Chẳng có ai. Đây là một quyết định thiết kế mà bạn phải đưa ra về ứng dụng cá nhân của mình (có thể cùng với nhóm của bạn).
Doc Brown

7
+1. Cụ thể, tôi sẽ lưu ý rằng không có sự khác biệt thực sự giữa SQL trong một phương thức và SQL trong một thủ tục được lưu trữ, về mặt "cái gì đó được mã hóa cứng", hoặc cách tái sử dụng, có thể duy trì, v.v. thủ tục có thể được thực hiện với một phương pháp. Tất nhiên các thủ tục có thể hữu ích, nhưng một quy tắc vẹt "chúng ta không thể có SQL trong các phương thức, vì vậy, hãy đưa tất cả vào quy trình" có thể sẽ tạo ra rất nhiều hành trình với rất ít lợi ích.

1
@ user82096 Tôi thường nói rằng việc đặt mã truy cập db vào SP đã gây bất lợi trong gần như mọi dự án tôi đã thấy. (MS stack) Ngoài sự suy giảm hiệu năng thực tế (bộ đệm kế hoạch thực thi cứng nhắc), việc bảo trì hệ thống trở nên khó khăn hơn bằng cách phân chia logic xung quanh và SP được duy trì bởi một nhóm người khác so với các nhà phát triển logic ứng dụng. Đặc biệt là trên Azure, nơi thay đổi mã giữa các Deployment Slots giống như vài giây làm việc, nhưng việc di chuyển lược đồ không phải mã đầu tiên / db-đầu tiên giữa các vị trí là một vấn đề đau đầu.
Sentinel

33

Marstato đưa ra một câu trả lời hay nhưng tôi muốn thêm một số bình luận.

SQL trong nguồn KHÔNG phải là một mô hình chống nhưng nó có thể gây ra vấn đề. Tôi có thể nhớ khi bạn từng phải đặt các truy vấn SQL vào các thuộc tính của các thành phần được thả vào mọi dạng. Điều đó làm cho mọi thứ thực sự xấu xí thực sự rất nhanh và bạn phải nhảy qua các vòng để tìm các truy vấn. Tôi trở thành một người ủng hộ mạnh mẽ việc tập trung truy cập Cơ sở dữ liệu càng nhiều càng tốt trong giới hạn của các ngôn ngữ tôi đang làm việc. Đồng nghiệp của bạn có thể nhận được hồi tưởng cho những ngày đen tối này.

Bây giờ, một số ý kiến ​​đang nói về việc khóa nhà cung cấp như nó tự động là một điều xấu. Không phải vậy. Nếu tôi ký một kiểm tra sáu con số mỗi năm để sử dụng Oracle, bạn có thể đặt cược rằng tôi muốn bất kỳ ứng dụng nào truy cập cơ sở dữ liệu đó được sử dụng cú pháp Oracle bổ sung một cách thích hợpnhưng đến mức đầy đủ nhất của nó. Tôi sẽ không vui nếu cơ sở dữ liệu sáng bóng của tôi bị tê liệt bởi các lập trình viên viết vanilla ANSI SQL một cách tồi tệ khi có một "cách Oracle" để viết SQL mà không làm tê liệt cơ sở dữ liệu. Đúng, việc thay đổi cơ sở dữ liệu sẽ khó hơn nhưng tôi chỉ thấy nó được thực hiện tại một trang web khách hàng lớn một vài lần trong hơn 20 năm và một trong những trường hợp đó đã chuyển từ DB2 -> Oracle vì máy tính lớn lưu trữ DB2 đã lỗi thời và bị ngừng hoạt động . Đúng, đó là khóa nhà cung cấp nhưng đối với khách hàng doanh nghiệp, thực sự mong muốn trả tiền cho một RDBMS có khả năng đắt tiền như Oracle hoặc Microsoft SQL Server và sau đó sử dụng nó đến mức tối đa. Bạn có một thỏa thuận hỗ trợ như chăn thoải mái của bạn. Nếu tôi đang trả tiền cho một cơ sở dữ liệu với việc thực hiện thủ tục được lưu trữ phong phú,

Điều này dẫn đến điểm tiếp theo, nếu bạn đang viết một ứng dụng truy cập Cơ sở dữ liệu SQL, bạn phải học SQL cũng như ngôn ngữ khác và bằng cách học, tôi có nghĩa là tối ưu hóa truy vấn; Tôi sẽ tức giận với bạn nếu bạn viết mã tạo SQL xóa bộ đệm SQL với một loạt các truy vấn gần như giống hệt nhau khi bạn có thể sử dụng một truy vấn được tham số hóa khéo léo.

Không có lời bào chữa, không trốn đằng sau một bức tường của Hibernate. Các ORM được sử dụng không tốt có thể thực sự làm tê liệt hiệu năng của các ứng dụng. Tôi nhớ đã thấy một câu hỏi trên Stack Overflow vài năm trước dọc theo dòng:

Trong Hibernate tôi đang lặp qua 250.000 bản ghi kiểm tra các giá trị của một vài thuộc tính và cập nhật các đối tượng phù hợp với các điều kiện nhất định. Nó chạy hơi chậm, tôi có thể làm gì để tăng tốc?

Làm thế nào về "CẬP NHẬT bảng SET field1 = trong đó trường2 là True và Field3> 100". Tạo và xử lý 250.000 đối tượng cũng có thể là vấn đề của bạn ...

tức là Bỏ qua Hibernate khi không thích hợp để sử dụng nó. Hiểu cơ sở dữ liệu.

Vì vậy, tóm lại, việc nhúng SQL vào mã có thể là một thực tiễn tồi tệ nhưng có những điều tồi tệ hơn nhiều mà bạn có thể sẽ cố gắng tránh nhúng SQL.


5
Tôi đã không nói "khóa nhà cung cấp" là điều xấu. Tôi tuyên bố nó đi kèm với sự đánh đổi. Trong thị trường ngày nay với db là xaaS, các hợp đồng và giấy phép cũ để chạy db tự lưu trữ sẽ ngày càng hiếm hơn. Ngày nay, việc thay đổi db từ nhà cung cấp A sang B khá dễ dàng so với 10 năm trước. Nếu bạn đọc các bình luận, tôi không ủng hộ việc tận dụng bất kỳ tính năng nào của việc lưu trữ dữ liệu. Vì vậy, thật dễ dàng để đưa một số chi tiết cụ thể của nhà cung cấp vào một cái gì đó (ứng dụng) có nghĩa là bất khả tri của nhà cung cấp. Chúng tôi cố gắng theo dõi SOLiD chỉ đến cuối khóa mã cho một bộ lưu trữ dữ liệu duy nhất. Không phải là một vấn đề lớn
Laiv

2
Đây là một câu trả lời tuyệt vời. Thường thì cách tiếp cận đúng là cách dẫn đến tình huống xấu nhất nếu mã xấu nhất có thể được viết. Mã ORM tồi tệ nhất có thể tồi tệ hơn nhiều so với SQL nhúng tồi tệ nhất có thể.
jwg

@Laiv điểm tốt PaaS là ​​một chút thay đổi trò chơi - Tôi sẽ phải suy nghĩ thêm về ý nghĩa.
đánh dấu

3
@jwg Tôi muốn nói rằng mã ORM trên trung bình kém hơn SQL nhúng trung bình :)
hủy bỏ

@macottle Giả sử rằng SQL nhúng trung bình dưới đây được viết bởi ppl trên mức trung bình của người viết ORM. Điều tôi nghi ngờ Nó rất nhiều. Nhiều nhà phát triển ngoài kia không có khả năng viết trái THAM GIA kiểm tra SO trước.
Laiv

14

Có, các chuỗi SQL mã hóa cứng thành mã ứng dụng thường là một mô hình chống.

Chúng ta hãy cố gắng bỏ qua sự khoan dung mà chúng ta đã phát triển sau nhiều năm nhìn thấy điều này trong mã sản xuất. Trộn các ngôn ngữ hoàn toàn khác nhau với cú pháp khác nhau trong cùng một tệp thường không phải là một kỹ thuật phát triển mong muốn. Điều này khác với các ngôn ngữ mẫu như Dao cạo được thiết kế để mang ý nghĩa theo ngữ cảnh cho nhiều ngôn ngữ. Như Sava B. đề cập trong một bình luận bên dưới, SQL trong C # hoặc ngôn ngữ ứng dụng khác của bạn (Python, C ++, v.v.) là một chuỗi giống như bất kỳ chuỗi nào khác và không có ý nghĩa về mặt ngữ nghĩa. Điều tương tự cũng áp dụng khi trộn nhiều hơn một ngôn ngữ trong hầu hết các trường hợp, mặc dù rõ ràng có những tình huống làm như vậy là chấp nhận được, chẳng hạn như lắp ráp nội tuyến trong C, các đoạn CSS nhỏ và dễ hiểu trong HTML (lưu ý rằng CSS được thiết kế để trộn với HTML ), và những người khác.

Mã sạch của Robert C. Martin, pg.  288 (Robert C. Martin về pha trộn ngôn ngữ, Clean Code , Chương 17, "Mùi mã và heuristic", trang 288)

Đối với câu trả lời này, tôi sẽ tập trung SQL (như được hỏi trong câu hỏi). Các vấn đề sau có thể xảy ra khi lưu trữ SQL dưới dạng tập hợp các chuỗi tách rời:

  • Cơ sở dữ liệu logic rất khó định vị. Bạn tìm kiếm gì để tìm tất cả các câu lệnh SQL của bạn? Chuỗi có "CHỌN", "CẬP NHẬT", "MERGE", v.v.?
  • Việc tái cấu trúc việc sử dụng cùng một SQL hoặc tương tự trở nên khó khăn.
  • Thêm hỗ trợ cho các cơ sở dữ liệu khác là khó khăn. Làm thế nào một người sẽ thực hiện điều này? Thêm câu lệnh if..then cho mỗi cơ sở dữ liệu và lưu trữ tất cả các truy vấn dưới dạng chuỗi trong phương thức?
  • Các nhà phát triển đọc một tuyên bố bằng ngôn ngữ khác và bị phân tâm bởi sự thay đổi trọng tâm từ mục đích của phương thức sang chi tiết triển khai của phương thức (cách thức và nơi lấy dữ liệu).
  • Mặc dù một lớp có thể không có quá nhiều vấn đề, các chuỗi SQL nội tuyến bắt đầu bị phá vỡ khi các câu lệnh trở nên phức tạp hơn. Bạn làm gì với một tuyên bố dòng 113? Đặt tất cả 113 dòng trong phương pháp của bạn?
  • Làm thế nào để nhà phát triển di chuyển hiệu quả các truy vấn qua lại giữa trình soạn thảo SQL (SSMS, SQL Developer, v.v.) và mã nguồn của họ? @Tiền tố của C # làm cho việc này dễ dàng hơn, nhưng tôi đã thấy rất nhiều mã trích dẫn từng dòng SQL và thoát khỏi dòng mới. "SELECT col1, col2...colN"\ "FROM painfulExample"\ "WHERE maintainability IS NULL"\ "AND modification.effort > @necessary"\
  • Các ký tự thụt đầu dòng được sử dụng để căn chỉnh SQL với mã ứng dụng xung quanh được truyền qua mạng với mỗi lần thực hiện. Điều này có thể không đáng kể đối với các ứng dụng quy mô nhỏ, nhưng nó có thể tăng lên khi mức độ sử dụng của phần mềm tăng lên.

Các ORM đầy đủ (Các trình ánh xạ quan hệ đối tượng như Entity Framework hoặc Hibernate) có thể loại bỏ SQL tiêu ngẫu nhiên trong mã ứng dụng. Việc sử dụng SQL và các tệp tài nguyên của tôi chỉ là một ví dụ. Các ORM, các lớp trợ giúp, v.v ... đều có thể giúp hoàn thành mục tiêu của mã sạch hơn.

Như Kevin đã nói trong một câu trả lời trước đó, SQL trong mã có thể được chấp nhận trong các dự án nhỏ, nhưng các dự án lớn bắt đầu như các dự án nhỏ và xác suất hầu hết các đội sẽ quay lại và thực hiện đúng tỷ lệ nghịch với kích thước mã.

Có nhiều cách đơn giản để giữ SQL trong một dự án. Một trong những phương pháp mà tôi thường sử dụng là đặt từng câu lệnh SQL vào tệp tài nguyên Visual Studio, thường được đặt tên là "sql". Tệp văn bản, tài liệu JSON hoặc nguồn dữ liệu khác có thể hợp lý tùy thuộc vào công cụ của bạn. Trong một số trường hợp, một lớp riêng dành riêng cho việc liên kết các chuỗi SQL có thể là tùy chọn tốt nhất, nhưng có thể có một số vấn đề được mô tả ở trên.

Ví dụ SQL: Cái nào trông thanh lịch hơn?:

using(DbConnection connection = Database.SystemConnection()) {
    var eyesoreSql = @"
    SELECT
        Viewable.ViewId,
        Viewable.HelpText,
        PageSize.Width,
        PageSize.Height,
        Layout.CSSClass,
        PaginationType.GroupingText
    FROM Viewable
    LEFT JOIN PageSize
        ON PageSize.Id = Viewable.PageSizeId
    LEFT JOIN Layout
        ON Layout.Id = Viewable.LayoutId
    LEFT JOIN Theme
        ON Theme.Id = Viewable.ThemeId
    LEFT JOIN PaginationType
        ON PaginationType.Id = Viewable.PaginationTypeId
    LEFT JOIN PaginationMenu
        ON PaginationMenu.Id = Viewable.PaginationMenuId
    WHERE Viewable.Id = @Id
    ";
    var results = connection.Query<int>(eyesoreSql, new { Id });
}

Trở thành

using(DbConnection connection = Database.SystemConnection()) {
    var results = connection.Query<int>(sql.GetViewable, new { Id });
}

SQL luôn ở trong một tệp dễ định vị hoặc tập hợp các tệp, mỗi tệp có một tên mô tả mô tả những gì nó làm thay vì cách thực hiện, mỗi tệp có một không gian cho một nhận xét sẽ không làm gián đoạn dòng mã ứng dụng :

SQL trong một tài nguyên

Phương pháp đơn giản này thực hiện một truy vấn đơn độc. Theo kinh nghiệm của tôi, các thang đo lợi ích khi sử dụng "ngoại ngữ" ngày càng tinh vi hơn. Việc tôi sử dụng một tệp tài nguyên chỉ là một ví dụ. Các phương pháp khác nhau có thể phù hợp hơn tùy thuộc vào ngôn ngữ (SQL trong trường hợp này) và nền tảng.

Phương pháp này và các phương pháp khác giải quyết danh sách trên theo cách sau:

  1. Mã cơ sở dữ liệu dễ dàng xác định vị trí vì nó đã được tập trung. Trong các dự án lớn hơn, nhóm like-SQL thành các tệp riêng biệt, có thể trong một thư mục có tên SQL.
  2. Hỗ trợ cho cơ sở dữ liệu thứ hai, thứ ba, vv dễ dàng hơn. Tạo một giao diện (hoặc trừu tượng ngôn ngữ khác) trả về các câu lệnh duy nhất của cơ sở dữ liệu. Việc triển khai cho mỗi cơ sở dữ liệu trở nên ít hơn các câu lệnh tương tự như: return SqlResource.DoTheThing;Đúng, các triển khai này có thể bỏ qua tài nguyên và chứa SQL trong một chuỗi, nhưng một số (không phải tất cả) các vấn đề ở trên vẫn sẽ xuất hiện.
  3. Tái cấu trúc rất đơn giản - chỉ cần sử dụng lại cùng một tài nguyên. Thậm chí, bạn có thể sử dụng cùng một mục nhập tài nguyên cho các hệ thống DBMS khác nhau với một vài câu lệnh định dạng. Tôi làm điều này thường xuyên.
  4. Sử dụng ngôn ngữ thứ cấp có thể sử dụng tên mô tả, ví dụ như sql.GetOrdersForAccountthay vì khó hiểu hơnSELECT ... FROM ... WHERE...
  5. Các câu lệnh SQL được triệu tập với một dòng bất kể kích thước và độ phức tạp của chúng.
  6. SQL có thể được sao chép và dán giữa các công cụ cơ sở dữ liệu như SSMS và SQL Developer mà không cần sửa đổi hoặc sao chép cẩn thận. Không có dấu ngoặc kép. Không có dấu gạch chéo ngược. Trong trường hợp trình soạn thảo tài nguyên Visual Studio cụ thể, một cú nhấp chuột làm nổi bật câu lệnh SQL. CTRL + C và sau đó dán nó vào trình soạn thảo SQL.

Việc tạo SQL trong một tài nguyên là nhanh chóng, do đó có rất ít động lực để trộn việc sử dụng tài nguyên với SQL-in-code.

Bất kể phương pháp được chọn, tôi đã thấy rằng các ngôn ngữ trộn thường làm giảm chất lượng mã. Tôi hy vọng rằng một số vấn đề và giải pháp được mô tả ở đây sẽ giúp các nhà phát triển loại bỏ mùi mã này khi thích hợp.


13
Tôi nghĩ rằng điều này tập trung quá nhiều vào một lời chỉ trích tồi về việc có SQL trong mã nguồn. Có hai ngôn ngữ khác nhau trong cùng một tệp không nhất thiết phải khủng khiếp. Nó phụ thuộc vào rất nhiều thứ như cách chúng có liên quan và cách chúng được trình bày.
jwg

9
"Trộn các ngôn ngữ hoàn toàn khác nhau với cú pháp khác nhau trong cùng một tệp" Đây là một đối số khủng khiếp. Nó cũng sẽ áp dụng cho công cụ xem dao cạo và HTML, CSS và Javascript. Yêu tiểu thuyết đồ họa của bạn!
Ian Newson

4
Điều này chỉ đẩy sự phức tạp ở một nơi khác. Có, mã ban đầu của bạn sạch hơn, với chi phí thêm một sự gián tiếp mà nhà phát triển hiện phải điều hướng đến cho mục đích bảo trì. Lý do thực sự bạn sẽ làm điều này là nếu mỗi câu lệnh SQL được sử dụng ở nhiều nơi trong mã. Theo cách đó, nó thực sự không khác với bất kỳ phép tái cấu trúc thông thường nào khác ("Phương pháp trích xuất").
Robert Harvey

3
Nói rõ hơn, đây không phải là câu trả lời cho câu hỏi "tôi phải làm gì với các chuỗi SQL của mình", giống như đó là câu trả lời cho câu hỏi "tôi phải làm gì với bất kỳ tập hợp các chuỗi đủ phức tạp nào", một câu hỏi câu trả lời của bạn hùng hồn giải quyết.
Robert Harvey

2
@RobertHarvey: Tôi chắc chắn rằng trải nghiệm của chúng tôi khác nhau, nhưng trong chính tôi, tôi đã tìm thấy sự trừu tượng trong câu hỏi là một chiến thắng trong hầu hết các trường hợp. Tôi chắc chắn sẽ tinh chỉnh sự đánh đổi trừu tượng của mình khi tôi đã thực hiện lên xuống trong nhiều năm và một ngày nào đó có thể đưa SQL trở lại mã. YMMV. :) Tôi nghĩ microservice có thể rất tuyệt và chúng thường tách biệt các chi tiết SQL của bạn (nếu SQL hoàn toàn được sử dụng) khỏi mã ứng dụng cốt lõi. Tôi ít ủng hộ "sử dụng phương pháp cụ thể của tôi: tài nguyên" và chủ trương hơn "Nói chung không trộn lẫn ngôn ngữ dầu và nước".
Charles Burns

13

Nó phụ thuộc. Có một số cách tiếp cận khác nhau có thể hoạt động:

  1. Mô đun hóa SQL và tách nó thành một tập hợp các lớp, hàm hoặc bất kỳ đơn vị trừu tượng nào mà mô hình của bạn sử dụng, sau đó gọi nó bằng logic ứng dụng.
  2. Chuyển tất cả SQL phức tạp vào các khung nhìn và sau đó chỉ thực hiện SQL rất đơn giản trong logic ứng dụng, do đó bạn không cần phải mô đun hóa bất cứ điều gì.
  3. Sử dụng một thư viện ánh xạ quan hệ đối tượng.
  4. YAGNI, chỉ cần viết SQL trực tiếp trong logic ứng dụng.

Như thường lệ, nếu dự án của bạn đã chọn một trong những kỹ thuật này, bạn nên nhất quán với phần còn lại của dự án.

(1) và (3) đều tương đối tốt trong việc duy trì tính độc lập giữa logic ứng dụng và cơ sở dữ liệu, theo nghĩa là ứng dụng sẽ tiếp tục biên dịch và vượt qua các thử nghiệm khói cơ bản nếu bạn thay thế cơ sở dữ liệu bằng một nhà cung cấp khác. Tuy nhiên, hầu hết các nhà cung cấp không hoàn toàn tuân thủ tiêu chuẩn SQL, do đó, việc thay thế bất kỳ nhà cung cấp nào bằng bất kỳ nhà cung cấp nào khác có thể yêu cầu thử nghiệm rộng rãi và tìm kiếm lỗi bất kể bạn sử dụng kỹ thuật nào. Tôi nghi ngờ rằng đây là một vấn đề lớn như mọi người đưa ra. Thay đổi cơ sở dữ liệu về cơ bản là giải pháp cuối cùng khi bạn không thể có được cơ sở dữ liệu hiện tại để đáp ứng nhu cầu của mình. Nếu điều đó xảy ra, có lẽ bạn đã chọn cơ sở dữ liệu kém.

Sự lựa chọn giữa (1) và (3) chủ yếu là vấn đề bạn thích ORM bao nhiêu. Theo tôi họ bị lạm dụng. Chúng là một đại diện kém của mô hình dữ liệu quan hệ, bởi vì các hàng không có danh tính theo cách mà các đối tượng có danh tính. Bạn có thể gặp phải các điểm đau xung quanh các ràng buộc duy nhất, tham gia và bạn có thể gặp khó khăn khi thể hiện một số truy vấn phức tạp hơn tùy thuộc vào sức mạnh của ORM. Mặt khác, (1) có thể sẽ yêu cầu nhiều mã hơn đáng kể so với ORM.

(2) hiếm khi được nhìn thấy, theo kinh nghiệm của tôi. Vấn đề là nhiều cửa hàng cấm SWE trực tiếp sửa đổi lược đồ cơ sở dữ liệu (vì "đó là công việc của DBA"). Đây không hẳn là một điều xấu trong bản thân nó; thay đổi lược đồ có một tiềm năng đáng kể để phá vỡ mọi thứ và có thể cần phải được triển khai cẩn thận. Tuy nhiên, để (2) hoạt động, ít nhất các SWE có thể giới thiệu các chế độ xem mới và sửa đổi các truy vấn sao lưu của các chế độ xem hiện tại với mức tối thiểu hoặc không quan liêu. Nếu đây không phải là trường hợp tại nơi bạn làm việc, (2) có thể sẽ không làm việc cho bạn.

Mặt khác, nếu bạn có thể làm cho (2) hoạt động, nó tốt hơn nhiều so với hầu hết các giải pháp khác vì nó giữ logic quan hệ trong SQL thay vì mã ứng dụng. Không giống như các ngôn ngữ lập trình mục đích chung, SQL được thiết kế riêng cho mô hình dữ liệu quan hệ và do đó tốt hơn trong việc thể hiện các truy vấn và biến đổi dữ liệu phức tạp. Các khung nhìn cũng có thể được chuyển cùng với phần còn lại của lược đồ của bạn khi thay đổi cơ sở dữ liệu, nhưng chúng sẽ làm cho các động thái đó trở nên phức tạp hơn.

Để đọc, các thủ tục được lưu trữ về cơ bản chỉ là một phiên bản crappier của (2). Tôi không đề xuất họ trong khả năng đó, nhưng bạn vẫn có thể muốn họ viết, nếu cơ sở dữ liệu của bạn không hỗ trợ các chế độ xem cập nhật hoặc nếu bạn cần làm gì đó phức tạp hơn là chèn hoặc cập nhật một hàng tại một thời điểm (ví dụ: giao dịch, đọc rồi viết, v.v.). Bạn có thể ghép thủ tục được lưu trữ của mình vào một khung nhìn bằng cách sử dụng kích hoạt (nghĩa làCREATE TRIGGER trigger_name INSTEAD OF INSERT ON view_name FOR EACH ROW EXECUTE PROCEDURE procedure_name;), nhưng ý kiến ​​khác nhau đáng kể về việc liệu đây có thực sự là một ý tưởng tốt hay không. Những người đề xuất sẽ cho bạn biết rằng nó giữ cho SQL rằng ứng dụng của bạn thực thi đơn giản nhất có thể. Những kẻ gièm pha sẽ nói với bạn rằng đây là một mức độ "ma thuật" không thể chấp nhận được và bạn chỉ nên thực hiện thủ tục trực tiếp từ ứng dụng của mình. Tôi muốn nói đây là một ý tưởng tốt hơn nếu thủ tục lưu trữ của bạn trông hoặc hoạt động rất giống một INSERT, UPDATEhoặc DELETE, và một ý tưởng tồi tệ hơn nếu nó đang làm cái gì khác. Cuối cùng, bạn sẽ phải tự quyết định phong cách nào có ý nghĩa hơn.

(4) là giải pháp không. Nó có thể là giá trị nó cho các dự án nhỏ, hoặc những dự án lớn chỉ tương tác lẻ tẻ với cơ sở dữ liệu. Nhưng đối với các dự án có nhiều SQL, đó không phải là ý kiến ​​hay vì bạn có thể có các bản sao hoặc biến thể của cùng một truy vấn nằm rải rác xung quanh ứng dụng của bạn, điều này cản trở khả năng đọc và tái cấu trúc.


2 như được viết về cơ bản giả định một cơ sở dữ liệu chỉ đọc. Các thủ tục được lưu trữ được sử dụng không phải là hiếm đối với các truy vấn sửa đổi.
jpmc26

@ jpmc26: Tôi bao gồm các bài viết trong ngoặc đơn ... bạn có đề xuất cụ thể nào để cải thiện câu trả lời này không?
Kevin

Hừm. Xin lỗi vì đã bình luận trước khi hoàn thành câu trả lời và sau đó bị phân tâm. Nhưng các khung nhìn cập nhật làm cho việc theo dõi nơi bảng đang được cập nhật khá khó khăn. Việc hạn chế cập nhật trực tiếp trên các bảng, bất kể cơ chế nào, đều có lợi thế về mặt hiểu logic của mã. Nếu bạn đang ràng buộc logic với DB, thì bạn không thể thực thi điều đó mà không có các thủ tục được lưu trữ. Họ cũng có lợi thế cho phép nhiều hoạt động với một cuộc gọi. Điểm mấu chốt: Tôi không nghĩ bạn nên quá khó khăn với họ.
jpmc26

@ jpmc26: Thật công bằng.
Kevin

8

Nó có được coi là một mô hình chống viết SQL trong mã nguồn không?

Không cần thiết. Nếu bạn đọc tất cả các ý kiến ​​ở đây, bạn sẽ tìm thấy các đối số hợp lệ cho các câu lệnh SQL mã hóa cứng trong mã nguồn.

Vấn đề đi kèm với nơi bạn đặt các báo cáo . Nếu bạn đặt các câu lệnh SQL trên khắp dự án, ở mọi nơi, có lẽ bạn sẽ bỏ qua một số nguyên tắc RẮN mà chúng ta thường cố gắng tuân theo.

cho rằng anh ta có ý; hoặc:

1) Sử dụng LINQ

hoặc là

2) Sử dụng các thủ tục được lưu trữ cho SQL

Chúng tôi không thể nói ý của anh ấy. Tuy nhiên, chúng ta có thể đoán. Ví dụ, điều đầu tiên tôi nghĩ đến là nhà cung cấp khóa . Các câu lệnh SQL mã hóa cứng có thể dẫn bạn kết hợp chặt chẽ ứng dụng của bạn với công cụ DB. Chẳng hạn, sử dụng các chức năng cụ thể của nhà cung cấp không tuân thủ ANSI.

Điều này không hẳn là sai cũng không tệ. Tôi chỉ chỉ vào thực tế.

Bỏ qua các nguyên tắc RẮN và khóa nhà cung cấp có thể có hậu quả bất lợi mà bạn có thể bỏ qua. Đó là lý do tại sao thường là tốt để ngồi với đội và phơi bày những nghi ngờ của bạn.

Lợi ích của các thủ tục được lưu trữ Tôi nghĩ là các Nhà phát triển SQL có thể tham gia vào quá trình phát triển (viết các thủ tục được lưu trữ, v.v.)

Tôi nghĩ rằng nó không có gì để làm với những lợi thế của các thủ tục được lưu trữ. Hơn nữa, nếu đồng nghiệp của bạn không thích SQL được mã hóa cứng, có khả năng việc chuyển doanh nghiệp sang các thủ tục được lưu trữ cũng sẽ không thích anh ta.

Chỉnh sửa: Liên kết sau đây nói về các câu lệnh SQL được mã hóa cứng:  https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/hard-coding-sql-statements . Có bất kỳ lợi ích của việc chuẩn bị một câu lệnh SQL?

Đúng. Các bài viết liệt kê những lợi thế của các tuyên bố chuẩn bị . Đây là một kiểu tạo khuôn mẫu SQL. An toàn hơn so với nối chuỗi. Nhưng bài viết không khuyến khích bạn đi theo cách này cũng như không xác nhận rằng bạn đúng. Nó chỉ giải thích làm thế nào chúng ta có thể sử dụng SQL được mã hóa một cách an toàn và hiệu quả.

Tóm tắt, hãy thử hỏi đồng nghiệp của bạn trước. Gửi mail, gọi điện cho anh ấy, ... Dù anh ấy có trả lời hay không, hãy ngồi cùng nhóm và phơi bày những nghi ngờ của bạn. Tìm giải pháp phù hợp nhất với yêu cầu của bạn. Đừng đưa ra các giả định sai dựa trên những gì bạn đọc được ngoài đó.


1
Cảm ơn. +1 cho "Các câu lệnh SQL mã hóa cứng có thể khiến bạn ghép chặt ứng dụng của bạn với công cụ db.". Tôi đi lang thang nếu anh ta đang đề cập đến SQL Server chứ không phải SQL, tức là sử dụng SQLConnection chứ không phải dbConnection; SQLCommand chứ không phải dbCommand và SQLDataReader chứ không phải dbDataReader.
w0051977

Không. Tôi đã đề cập đến việc sử dụng các biểu thức không tuân thủ ANSI. Ví dụ: select GETDATE(), ....GETDATE () là hàm ngày của SqlServer. Trong các công cụ khác, chức năng có tên khác nhau, biểu hiện khác nhau, ...
Laiv

14
"Người bán hàng lock-in" ... Bao lâu người / doanh nghiệp thực sự di chuyển cơ sở dữ liệu sản phẩm hiện có của họ để RDBMS khác? Ngay cả trong các dự án sử dụng ORM độc quyền, tôi chưa bao giờ thấy điều đó xảy ra: thông thường phần mềm cũng được viết lại từ đầu, bởi vì nhu cầu đã thay đổi ở giữa. Do đó, suy nghĩ về điều này có vẻ khá giống như "tối ưu hóa sớm" đối với tôi. Vâng, đó là hoàn toàn chủ quan.
Olivier Grégoire

1
Tôi không quan tâm làm thế nào thường xảy ra. Tôi quan tâm Nó có thể xảy ra. Trong các dự án greenfield, chi phí thực hiện DAL được trừu tượng hóa từ db là gần 0. Một di chuyển có thể là không. Các đối số chống lại ORM khá yếu. Các ORM không giống như 15 năm trước khi Hibernate khá xanh. Những gì tôi đã thấy là rất nhiều cấu hình "mặc định" và thiết kế mô hình dữ liệu khá tệ. Nó giống như nhiều công cụ khác, nhiều người thực hiện hướng dẫn "bắt đầu" và họ không quan tâm đến những gì xảy ra dưới mui xe. Công cụ không phải là vấn đề. Vấn đề là ai không biết sử dụng nó như thế nào và khi nào.
Laiv

Mặt khác, nhà cung cấp bị khóa không hẳn là xấu. Nếu tôi được hỏi tôi sẽ nói tôi không thích . Tuy nhiên, tôi đã bị khóa với Spring, Tomcat hoặc JBoss hoặc Websphere (vẫn tệ hơn). Những người tôi có thể tránh, tôi làm. Những người tôi không thể sống với nó. Đó là vấn đề sở thích.
Laiv

3

Tôi nghĩ rằng đó là một thực hành xấu, vâng. Những người khác đã chỉ ra những lợi thế của việc giữ tất cả mã truy cập dữ liệu của bạn trong lớp riêng của nó. Bạn không cần phải tìm kiếm nó, việc tối ưu hóa và kiểm tra sẽ dễ dàng hơn ... Nhưng ngay cả trong lớp đó, bạn có một vài lựa chọn: sử dụng ORM, sử dụng sprocs hoặc nhúng truy vấn SQL dưới dạng chuỗi. Tôi muốn nói rằng các chuỗi truy vấn SQL là lựa chọn tồi tệ nhất.

Với ORM, việc phát triển trở nên dễ dàng hơn rất nhiều và ít bị lỗi hơn. Với EF, bạn xác định lược đồ của mình chỉ bằng cách tạo các lớp mô hình của bạn (dù sao bạn cũng cần phải tạo các lớp này). Truy vấn bằng LINQ rất đơn giản - bạn thường tránh xa với 2 dòng c # trong đó nếu không bạn cần phải viết và duy trì một sproc. IMO, điều này có một lợi thế rất lớn khi nói đến năng suất và khả năng bảo trì - ít mã hơn, ít vấn đề hơn. Nhưng có một chi phí hoạt động, ngay cả khi bạn biết bạn đang làm gì.

Sprocs (hoặc chức năng) là tùy chọn khác. Tại đây, bạn viết các truy vấn SQL của mình theo cách thủ công. Nhưng ít nhất bạn có được một số đảm bảo rằng họ là chính xác. Nếu bạn đang làm việc trong .NET, Visual Studio thậm chí sẽ đưa ra các lỗi biên dịch nếu SQL không hợp lệ. Điều đó thật tuyệt. Nếu bạn thay đổi hoặc xóa một số cột và một số truy vấn của bạn trở nên không hợp lệ, ít nhất bạn có thể tìm hiểu về nó trong thời gian biên dịch. Việc duy trì sprocs trong các tệp của riêng họ cũng dễ dàng hơn - có thể bạn sẽ nhận được cú pháp tô sáng, tự động hoàn thành..v.v.

Nếu các truy vấn của bạn được lưu trữ dưới dạng sprocs, bạn cũng có thể thay đổi chúng mà không cần biên dịch lại và triển khai lại ứng dụng. Nếu bạn nhận thấy rằng một cái gì đó trong SQL của bạn bị hỏng, một DBA chỉ có thể sửa nó mà không cần phải có quyền truy cập vào mã ứng dụng của bạn. Nói chung, nếu các truy vấn của bạn ở dạng chuỗi ký tự, thì dbas không thể thực hiện công việc của chúng gần như dễ dàng.

Các truy vấn SQL dưới dạng chuỗi ký tự cũng sẽ làm cho mã truy cập c # của bạn khó đọc hơn.

Cũng như một quy tắc của ngón tay cái, hằng số ma thuật là xấu. Điều đó bao gồm chuỗi ký tự.


Việc cho phép các DBA thay đổi SQL của bạn mà không cập nhật ứng dụng là chia ứng dụng của bạn thành hai thực thể được triển khai riêng biệt, được phát triển riêng biệt. Bây giờ bạn cần quản lý hợp đồng giao diện giữa các giao diện đó, đồng bộ hóa việc phát hành các thay đổi phụ thuộc lẫn nhau, v.v ... Đây có thể là điều tốt hoặc điều xấu, nhưng nó còn hơn cả "đặt tất cả SQL của bạn vào một nơi", đó là một điều xa - quyết định kiến ​​trúc.
IMSoP

2

Nó không phải là một mô hình chống (câu trả lời này rất nguy hiểm gần với ý kiến). Nhưng định dạng mã là quan trọng và chuỗi SQL phải được định dạng để nó tách biệt rõ ràng với mã sử dụng nó. Ví dụ

    string query = 
    @"SELECT foo, bar
      FROM table
      WHERE id = @tn";

7
Vấn đề rõ ràng nhất với vấn đề này là vấn đề giá trị 42 đến từ đâu. Bạn đang nối giá trị đó vào chuỗi? Nếu vậy, nó đến từ đâu? Làm thế nào nó đã được kiểm tra để giảm thiểu các cuộc tấn công tiêm nhiễm SQL? Tại sao ví dụ này không hiển thị một truy vấn tham số?
Craig

Tôi chỉ có nghĩa là để hiển thị các định dạng. Xin lỗi, tôi quên tham số hóa nó. Bây giờ đã được sửa sau khi tham khảo msdn.microsoft.com/l
Library / bb738521 (v = vs.100) .aspx

+1 về tầm quan trọng của định dạng, mặc dù tôi duy trì rằng các chuỗi SQL là một mùi mã bất kể định dạng.
Charles Burns

1
Bạn có khăng khăng sử dụng ORM không? Khi ORM không được sử dụng, đối với một dự án nhỏ hơn, tôi sử dụng lớp 'shim' có chứa SQL nhúng.
rleir

Chuỗi SQL chắc chắn không phải là một mùi mã. Nếu không có ORM, với tư cách là người quản lý và kiến ​​trúc sư, tôi sẽ khuyến khích họ vượt qua SP vì cả lý do bảo trì và đôi khi là hiệu suất.
Sentinel

1

Tôi không thể nói cho bạn biết đồng nghiệp của bạn có ý gì. Nhưng tôi có thể trả lời điều này:

Có bất kỳ lợi ích của việc chuẩn bị một câu lệnh SQL?

. Sử dụng các câu lệnh được chuẩn bị với các biến bị ràng buộc là biện pháp bảo vệ chống lại việc tiêm SQL , đây vẫn là rủi ro bảo mật lớn nhất đối với các ứng dụng web trong hơn một thập kỷ . Cuộc tấn công này rất phổ biến, nó đã được đưa vào truyện tranh web gần mười năm trước và đây là thời điểm phòng thủ hiệu quả cao đã được triển khai.

... Và cách phòng thủ hiệu quả nhất để nối chuỗi các chuỗi truy vấn không phải là biểu diễn các truy vấn dưới dạng các chuỗi ở vị trí đầu tiên, mà là sử dụng API truy vấn an toàn loại để xây dựng các truy vấn. Chẳng hạn, đây là cách tôi viết truy vấn của mình bằng Java với QueryDSL:

List<UUID> ids = select(person.id).from(person).fetch();

Như bạn có thể thấy, không có một chuỗi ký tự nào ở đây, khiến cho việc tiêm SQL không thể thực hiện được. Hơn nữa, tôi đã hoàn thành mã khi viết này và IDE của tôi có thể cấu trúc lại nó nếu tôi chọn đổi tên cột id. Ngoài ra, tôi có thể dễ dàng tìm thấy tất cả các truy vấn cho bảng người bằng cách hỏi IDE của tôi nơi personbiến được truy cập. Ồ, và bạn có nhận thấy nó khá ngắn và dễ nhìn hơn mã của bạn không?

Tôi chỉ có thể giả định rằng một cái gì đó như thế này cũng có sẵn cho C #. Ví dụ, tôi nghe những điều tuyệt vời về LINQ.

Tóm lại, việc biểu diễn các truy vấn dưới dạng các chuỗi SQL khiến IDE khó có thể hỗ trợ một cách có ý nghĩa trong việc viết và tái cấu trúc các truy vấn, trì hoãn phát hiện cú pháp và lỗi loại từ thời gian biên dịch để chạy thời gian và là nguyên nhân góp phần gây ra lỗ hổng SQL SQL [1]. Vì vậy, có, có những lý do hợp lệ tại sao người ta có thể không muốn các chuỗi SQL trong mã nguồn.

[1]: Có, việc sử dụng đúng các câu lệnh đã chuẩn bị cũng ngăn ngừa việc tiêm SQL. Nhưng câu trả lời khác trong chủ đề này dễ bị tấn công SQL cho đến khi một nhà bình luận chỉ ra điều này không truyền cảm hứng cho niềm tin vào các lập trình viên cơ sở sử dụng chúng một cách chính xác bất cứ khi nào cần thiết ...


Để rõ ràng: Sử dụng các câu lệnh được chuẩn bị không ngăn chặn việc tiêm SQL. Sử dụng các báo cáo chuẩn bị với các biến ràng buộc nào. Có thể sử dụng các câu lệnh được chuẩn bị được xây dựng từ dữ liệu không đáng tin cậy.
Andy Lester

1

Rất nhiều câu trả lời tuyệt vời ở đây. Ngoài những gì đã được nói, tôi muốn thêm một điều nữa.

Tôi không xem xét việc sử dụng SQL nội tuyến là một mô hình chống. Tuy nhiên, những gì tôi làm xem xét một mô hình chống là mọi lập trình viên làm việc riêng của họ. Bạn phải quyết định như một đội theo một tiêu chuẩn chung. Nếu mọi người đang sử dụng linq, thì bạn sử dụng linq, nếu mọi người đang sử dụng lượt xem và các thủ tục được lưu trữ thì bạn làm điều đó.

Luôn luôn giữ một tâm trí cởi mở và đừng rơi vào giáo điều. Nếu cửa hàng của bạn là một cửa hàng "linq", bạn sử dụng nó. Ngoại trừ một nơi mà linq hoàn toàn không hoạt động. (Nhưng bạn không nên 99,9% thời gian.)

Vì vậy, những gì tôi sẽ làm là nghiên cứu mã trong cơ sở mã và kiểm tra cách các đồng nghiệp của bạn làm việc.


+1 Điểm tốt. Khả năng hỗ trợ quan trọng hơn hầu hết các cân nhắc khác vì vậy đừng quá thông minh :) Điều đó nói rằng, nếu bạn là một cửa hàng ORM đừng quên rằng có những trường hợp ORM không phải là câu trả lời và bạn cần phải viết SQL trực tiếp. Đừng tối ưu hóa sớm nhưng sẽ có lúc trong bất kỳ ứng dụng không tầm thường nào khi bạn sẽ phải đi theo tuyến đường này.
hủy hoại

0

Mã trông giống như từ lớp tương tác cơ sở dữ liệu nằm giữa cơ sở dữ liệu và phần còn lại của mã. Nếu thực sự như vậy, đây không phải là chống mẫu.

Phương thức này là một phần của lớp, ngay cả khi OP nghĩ khác (truy cập cơ sở dữ liệu đơn giản, không trộn lẫn với bất kỳ thứ gì khác). Nó có thể chỉ được đặt xấu bên trong mã. Phương thức này thuộc về lớp riêng biệt, "lớp giao thoa cơ sở dữ liệu". Sẽ là chống mẫu khi đặt nó bên trong lớp thông thường bên cạnh các phương thức triển khai các hoạt động phi cơ sở dữ liệu.

Kiểu chống sẽ là gọi SQL từ một số vị trí mã ngẫu nhiên khác. Bạn cần xác định một lớp giữa cơ sở dữ liệu và phần còn lại của mã, nhưng không phải là bạn hoàn toàn phải sử dụng một số công cụ phổ biến có thể hỗ trợ bạn ở đó.


0

Theo tôi, không phải là một mẫu chống nhưng bạn sẽ thấy mình xử lý khoảng cách định dạng chuỗi, đặc biệt đối với các truy vấn lớn không thể phù hợp trong một dòng.

Một ưu điểm khác là nó trở nên khó khăn hơn nhiều khi xử lý các truy vấn động nên được xây dựng theo các điều kiện nhất định.

var query = "select * from accounts";

if(users.IsInRole('admin'))
{
   query += " join secret_balances";
}

Tôi đề nghị sử dụng một trình xây dựng truy vấn sql


Có thể bạn chỉ sử dụng tốc ký nhưng thực sự là một ý tưởng tồi khi sử dụng "CHỌN *" một cách mù quáng bởi vì bạn sẽ mang lại các trường bạn không cần (băng thông !!) Ngoài ra mặc dù tôi không gặp vấn đề gì với mệnh đề Quản trị viên có điều kiện nó dẫn xuống một con dốc rất trơn trượt đến một mệnh đề "WHERE" có điều kiện và đó là một con đường dẫn thẳng đến địa ngục hiệu suất.
tẩy chay

0

Đối với nhiều tổ chức hiện đại với các đường ống triển khai nhanh chóng, nơi các thay đổi mã có thể được biên dịch, kiểm tra và đẩy vào sản xuất trong vài phút, việc nhúng các câu lệnh SQL vào mã ứng dụng là hoàn toàn hợp lý. Đây không nhất thiết là một mô hình chống phụ thuộc vào cách bạn đi về nó.

Một trường hợp hợp lệ để sử dụng các quy trình được lưu trữ ngày nay là trong các tổ chức có rất nhiều quy trình xung quanh việc triển khai sản xuất có thể liên quan đến nhiều tuần của chu kỳ QA, v.v. các truy vấn trong các thủ tục được lưu trữ.

Trừ khi bạn ở trong tình huống này, tôi khuyên bạn nên nhúng SQL vào mã ứng dụng của mình. Đọc các câu trả lời khác trong chủ đề này để được tư vấn về cách tốt nhất để đi về nó.


Văn bản gốc dưới đây cho bối cảnh

Ưu điểm chính của các thủ tục được lưu trữ là bạn có thể tối ưu hóa hiệu suất cơ sở dữ liệu mà không cần biên dịch lại và triển khai lại ứng dụng của bạn.

Trong nhiều tổ chức, mã chỉ có thể được đẩy sang sản xuất sau một chu kỳ QA, vv có thể mất vài ngày hoặc vài tuần. Nếu hệ thống của bạn phát triển vấn đề về hiệu suất cơ sở dữ liệu do thay đổi kiểu sử dụng hoặc tăng kích thước bảng, v.v. thì có thể khá khó khăn để theo dõi vấn đề với các truy vấn được mã hóa cứng, trong khi cơ sở dữ liệu sẽ có các công cụ / báo cáo, v.v. . Với các thủ tục lưu trữ, các giải pháp có thể được kiểm tra / đo điểm chuẩn trong sản xuất và vấn đề có thể được khắc phục nhanh chóng mà không cần phải đẩy phiên bản mới của phần mềm ứng dụng.

Nếu vấn đề này không quan trọng trong hệ thống của bạn thì đó là một quyết định hoàn toàn hợp lệ đối với các câu lệnh SQL mã cứng vào ứng dụng.


Sai ...........
Sentinel

Bạn có nghĩ rằng nhận xét của bạn là hữu ích cho bất cứ ai?
bikeman868

Điều này chỉ đơn giản là không chính xác. Giả sử chúng ta có một dự án API Web2 với EF là quyền truy cập dữ liệu và Azure Sql làm bộ lưu trữ. Không, chúng ta hãy loại bỏ EF và sử dụng SQL thủ công. Lược đồ db được lưu trữ trong dự án SSDT SQL Server. db trong Azure. Thay đổi mã liên quan đến việc đẩy ra một vị trí triển khai Dịch vụ Ứng dụng, mất 2 giây. Cộng với SQL thủ công có hiệu năng vượt trội so với các thủ tục được lưu trữ, nói chung, mặc dù "khôn ngoan" ngược lại.
Sentinel

Trong trường hợp của bạn, việc triển khai có thể mất vài giây, nhưng đây không phải là trường hợp của nhiều người. Tôi không nói rằng các thủ tục được lưu trữ là tốt hơn, chỉ là chúng có một số lợi thế trong một số trường hợp. Tuyên bố cuối cùng của tôi là nếu những trường hợp này không áp dụng thì việc đưa SQL vào ứng dụng là rất hợp lệ. Làm thế nào điều này mâu thuẫn với những gì bạn đang nói?
bikeman868

Thủ tục lưu trữ được tạo thủ công SQL ???
bikeman868
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.