Các ORM có cho phép tạo các mô hình miền phong phú không?


21

Sau khi sử dụng Hibernate trên hầu hết các dự án của tôi trong khoảng 8 năm, tôi đã đến một công ty không khuyến khích sử dụng và muốn các ứng dụng chỉ tương tác với DB thông qua các thủ tục được lưu trữ.

Sau khi thực hiện điều này trong một vài tuần, tôi đã không thể tạo ra một mô hình miền phong phú của ứng dụng mà tôi bắt đầu xây dựng và ứng dụng trông giống như một kịch bản giao dịch (khủng khiếp).

Một số vấn đề tôi tìm thấy là:

  • Không thể điều hướng biểu đồ đối tượng vì các thủ tục được lưu trữ chỉ tải lượng dữ liệu tối thiểu, điều đó có nghĩa là đôi khi chúng ta có các đối tượng tương tự với các trường khác nhau. Một ví dụ là: chúng tôi có một quy trình được lưu trữ để truy xuất tất cả dữ liệu từ khách hàng và một quy trình khác để truy xuất thông tin tài khoản cộng với một vài trường từ khách hàng.
  • Rất nhiều logic kết thúc trong các lớp của trình trợ giúp, do đó mã trở nên có cấu trúc hơn (với các thực thể được sử dụng như các cấu trúc C cũ).
  • Mã giàn giáo nhàm chán hơn, vì không có khung trích xuất các tập kết quả từ một thủ tục được lưu trữ và đặt nó vào một thực thể.

Câu hỏi của tôi là:

  • có ai gặp tình huống tương tự và không đồng ý với cách tiếp cận thủ tục cửa hàng không? bạn đã làm gì?
  • Có một lợi ích thực sự của việc sử dụng các thủ tục được lưu trữ? ngoài quan điểm ngớ ngẩn "không ai có thể đưa ra bảng thả".
  • Có cách nào để tạo một miền phong phú bằng cách sử dụng các thủ tục được lưu trữ không? Tôi biết rằng có khả năng sử dụng AOP để tiêm DAO / Kho lưu trữ vào các thực thể để có thể điều hướng biểu đồ đối tượng. Tôi không thích tùy chọn này vì nó rất gần với voodoo.

Phần kết luận

Đầu tiên, cảm ơn tất cả các câu trả lời của bạn. Kết luận mà tôi đã đưa ra là các ORM không cho phép tạo các mô hình Rich Domain (như một số người đã đề cập), nhưng nó đơn giản hóa số lượng công việc (thường lặp đi lặp lại). Sau đây là giải thích chi tiết hơn về kết luận, nhưng không dựa trên bất kỳ dữ liệu cứng nào.

Hầu hết các ứng dụng yêu cầu và gửi thông tin đến các hệ thống khác. Để làm điều này, chúng tôi tạo ra một sự trừu tượng trong các điều khoản mô hình (ví dụ: một sự kiện kinh doanh) và mô hình miền gửi hoặc nhận sự kiện. Sự kiện thường cần một tập hợp nhỏ thông tin từ mô hình, nhưng không phải toàn bộ mô hình. Ví dụ: trong một cửa hàng trực tuyến, một cổng thanh toán yêu cầu một số thông tin người dùng và tổng số để tính phí người dùng, nhưng không yêu cầu lịch sử mua hàng, các sản phẩm có sẵn và tất cả các cơ sở khách hàng. Vì vậy, sự kiện này có một bộ dữ liệu nhỏ và cụ thể.

Nếu chúng ta lấy cơ sở dữ liệu của một ứng dụng làm hệ thống bên ngoài, thì chúng ta cần tạo ra một sự trừu tượng cho phép chúng ta ánh xạ các thực thể Mô hình miền vào cơ sở dữ liệu ( như NimChimpsky đã đề cập , sử dụng trình ánh xạ dữ liệu). Sự khác biệt rõ ràng là bây giờ chúng ta cần tạo thủ công ánh xạ cho từng thực thể mô hình vào cơ sở dữ liệu (có thể là lược đồ kế thừa hoặc các thủ tục được lưu trữ), với một nỗi đau thêm, vì hai thực thể này không đồng bộ hóa, một thực thể miền có thể ánh xạ một phần đến một thực thể cơ sở dữ liệu (ví dụ: lớp UserCredentials chỉ chứa tên người dùng và mật khẩu được ánh xạ tới bảng Người dùng có các cột khác) hoặc một thực thể mô hình miền có thể ánh xạ tới nhiều thực thể cơ sở dữ liệu (ví dụ: nếu có một thực thể cơ sở dữ liệu một ánh xạ trên bảng, nhưng chúng tôi muốn tất cả dữ liệu chỉ trong một lớp).

Trong một ứng dụng có một vài thực thể, số lượng công việc làm thêm có thể nhỏ nếu không cần phải vượt qua các thực thể, nhưng nó sẽ tăng lên khi có nhu cầu có điều kiện để vượt qua các thực thể (và do đó chúng ta có thể muốn thực hiện một loại 'lười biếng tải'). Khi một ứng dụng phát triển để có nhiều thực thể hơn, công việc này chỉ tăng lên (và tôi có cảm giác rằng nó tăng phi tuyến tính). Giả định của tôi ở đây, là chúng tôi không cố gắng phát minh lại ORM.

Một lợi ích của việc coi DB là một hệ thống bên ngoài, là chúng ta có thể viết mã xung quanh các tình huống trong đó chúng ta muốn có 2 phiên bản khác nhau của một ứng dụng đang chạy, trong đó mỗi ứng dụng có một ánh xạ khác nhau. Điều này trở nên thú vị hơn trong kịch bản giao hàng liên tục cho sản xuất ... nhưng tôi nghĩ điều này cũng có thể xảy ra với các ORM ở mức độ thấp hơn.

Tôi sẽ loại bỏ khía cạnh bảo mật, trên cơ sở rằng một nhà phát triển, ngay cả khi anh ta không có quyền truy cập vào cơ sở dữ liệu, có thể có được hầu hết nếu không phải tất cả thông tin được lưu trữ trong hệ thống, chỉ bằng cách tiêm mã độc (ví dụ: Tôi không thể tin rằng tôi đã quên xóa dòng ghi nhật ký chi tiết thẻ tín dụng của khách hàng, thưa ông chủ! ).


Cập nhật nhỏ (ngày 6 tháng 6 năm 2012)

Các thủ tục được lưu trữ (ít nhất là trong Oracle) ngăn chặn thực hiện bất cứ điều gì như phân phối liên tục với thời gian chết bằng 0, vì bất kỳ thay đổi nào đối với cấu trúc của các bảng sẽ làm mất hiệu lực các thủ tục và trình kích hoạt. Vì vậy, trong thời gian DB đang được cập nhật, ứng dụng cũng sẽ ngừng hoạt động. Oracle cung cấp một giải pháp cho Định nghĩa dựa trên Phiên bản này , nhưng một số DBA tôi đã hỏi về tính năng này đã đề cập rằng nó được cấy ghép kém và họ sẽ không đưa nó vào DB sản xuất.


Chà, rõ ràng bạn có thể làm những gì Hibernate làm và sử dụng tính kế thừa để tạo một đối tượng proxy động, cho phép bạn truy xuất biểu đồ đối tượng. Điều đó cực kỳ khó khăn với SP mặc dù: D
Max

Vì vậy, tôi sẽ kết thúc việc tái tạo một nửa của ngủ đông, mà không có hơn 10 năm kinh nghiệm mà nhóm ngủ đông có :).
Augusto

1
Bất kỳ DBA nào cũng nên ngăn việc bỏ các bảng cụ thể của một số người dùng. Nó không quan trọng bằng cách bạn cố gắng làm điều đó.
JeffO

1
Bạn có thể xem Mybatis - nó có thể cung cấp tính năng bạn cần. Đó là một ORM ít hơn một khung ánh xạ. Bạn có thể viết SQL theo cách bạn thích và cho Mybatis biết nơi đặt nó trên mô hình đối tượng của bạn. Nó sẽ xử lý các biểu đồ đối tượng lớn với nhiều truy vấn, nghe có vẻ giống như tình huống bạn có (rất nhiều thủ tục được lưu trữ mỏng).
Michael K

1
@Augusto: Tôi đã ở trong một tình huống tương tự, không phải do sử dụng SP, mà do sử dụng khung ánh xạ độc quyền không hỗ trợ các mối quan hệ đối tượng. Chúng tôi đã dành nhiều ngày để viết mã có thể được viết trong vài phút bằng cách sử dụng ORM thích hợp. Tôi chưa bao giờ giải quyết vấn đề đó.
kevin cline

Câu trả lời:


16

Ứng dụng của bạn vẫn phải được mô hình hóa từ các nguyên tắc thiết kế hướng tên miền. Cho dù bạn sử dụng ORM, JDBC thẳng, gọi SP (hoặc bất cứ điều gì) đều không thành vấn đề . Hy vọng rằng một lớp mỏng trừu tượng mô hình của bạn từ các SP sẽ thực hiện thủ thuật trong trường hợp này. Như một poster khác đã nêu , bạn nên xem SP và kết quả của chúng dưới dạng dịch vụ và ánh xạ kết quả vào mô hình miền của bạn.


Martijn, tôi đồng ý rằng ứng dụng nên được mô hình hóa bằng các nguyên tắc DDD, nhưng vấn đề tôi gặp phải (và xin vui lòng cho tôi biết nếu có giải pháp !!) là một số procs được lưu trữ trả lại rất ít thông tin để khởi tạo một thực thể DDD. Vui lòng xem bình luận này nơi tôi đã giải thích thêm một chút về thông tin mà các thủ tục được lưu trữ trả về. Tôi có thể phá vỡ điều này, bằng cách gọi nhiều hơn một Proc được lưu trữ, và ví dụ như lấy tất cả các chi tiết người dùng và sau đó gọi một chi tiết khác để lấy tất cả thông tin tài khoản, nhưng cảm thấy sai :).
Augusto

1
@Augusto Chà ... bạn là nhà phát triển ứng dụng, vì vậy bạn phải quyết định xem có tồn tại đối tượng nhất định với các trường nhất định được đặt thành NULL hay không. Nếu nó có ý nghĩa (ví dụ cho một số nhiệm vụ nhất định) thì hãy để nó được. Nếu không, hãy yêu cầu tác giả của SP cung cấp thêm dữ liệu, để bạn có thể tạo các đối tượng của mình.
Jacek Prucia

Và thêm vào nhận xét của Jacek - thực sự hoàn toàn chấp nhận được khi gọi 2+ procs được lưu trữ, một lần nữa nghĩ về chúng như hai dịch vụ từ xa mà bạn phải gọi để tạo mô hình miền của mình, không có gì sai với điều đó :-).
Martijn Verburg

@Martijn: Theo kinh nghiệm của tôi, một lớp mỏng là không đủ. Mã ánh xạ có thể dài hơn đáng kể so với logic nghiệp vụ cơ bản.
kevin cline

@Kevin cline - Điểm hay, đã đặt 'hy vọng' vào câu trả lời :-)
Martijn Verburg

5

Có một lợi ích thực sự của việc sử dụng các thủ tục được lưu trữ?

Trong thế giới tài chính (và những nơi bắt buộc phải tuân thủ Sarbanes-Oxley ), bạn cần có khả năng kiểm toán các hệ thống để đảm bảo rằng họ làm những gì họ phải làm. Trong những trường hợp này, việc đảm bảo tuân thủ sẽ dễ dàng hơn nhiều khi tất cả các truy cập dữ liệu đều thông qua các thủ tục được lưu trữ. Và khi tất cả SQL ad-hoc bị loại bỏ, việc che giấu mọi thứ sẽ khó khăn hơn nhiều. Để biết ví dụ về lý do tại sao điều này sẽ là một "điều tốt", tôi giới thiệu bạn đến bài viết phản ánh kinh điển của Ken Thompson về Sự tin tưởng .


vâng một triệu lần có! Bạn cũng cần đảm bảo rằng người dùng không thể thực hiện bất kỳ điều gì họ không cần phải làm bao gồm cả việc không có quyền trực tiếp đối với các bảng và các procs được lưu trữ giúp ích rất nhiều.
HLGEM

1
Tôi làm việc cho một công ty đại chúng và chúng tôi là SOX sompliant. Đó có thể là kiến ​​thức kém về kiểm toán của tôi, nhưng tôi không thấy sự khác biệt giữa thực hiện kiểm toán ở cấp DB (thông qua các procs được lưu trữ) hoặc ở cấp ứng dụng. Mỗi ứng dụng nên có lược đồ DB riêng và lược đồ đó chỉ có thể truy cập được từ ứng dụng, thay vì chia sẻ giữa các ứng dụng khác nhau.
Augusto

liên kết bị hỏng ...
Alex R

@AlexR, liên kết cố định
Tangurena

2

Các thủ tục được lưu trữ hiệu quả hơn rất nhiều so với mã SQL phía máy khách. Họ biên dịch trước SQL trong DB cũng cho phép nó thực hiện một số tối ưu hóa.

Về mặt kiến ​​trúc, một SP sẽ trả về dữ liệu tối thiểu cần thiết cho một nhiệm vụ, điều này tốt vì điều đó có nghĩa là ít dữ liệu được truyền đi. Nếu bạn có một kiến ​​trúc như vậy, bạn cần nghĩ về DB như một dịch vụ (nghĩ về nó như một dịch vụ web và mỗi SP là một phương thức để gọi). Không nên làm việc với nó như thế này, trong khi ORM hướng dẫn bạn làm việc với dữ liệu từ xa như thể nó là cục bộ, do đó lừa bạn giới thiệu các vấn đề về hiệu suất nếu bạn không cẩn thận.

Tôi đã ở trong tình huống chúng tôi sử dụng SP hoàn toàn, DB đã cung cấp API dữ liệu và chúng tôi đã sử dụng nó. Ứng dụng đặc biệt đó có quy mô rất lớn và hoạt động rất tốt. Tôi sẽ không có bất cứ điều gì xấu nói về SP sau đó!

Có một lợi thế khác - các DBA sẽ viết tất cả các truy vấn SQL cho bạn và sẽ vui vẻ xử lý tất cả các cấu trúc phân cấp quan hệ trong DB, do đó bạn không phải làm vậy.


3
gbjbaanb, hầu hết những gì bạn nói là đúng với cơ sở dữ liệu cũ. Hầu hết các cơ sở dữ liệu mới hơn biên dịch lại các truy vấn khá thường xuyên để quyết định nên sử dụng tối ưu hóa mới nào (ngay cả khi chúng được lưu trữ được sản xuất). Tôi đồng ý với những gì bạn nói về việc sử dụng DB như một hệ thống bên ngoài, nhưng tôi cũng thấy rằng có rất nhiều công việc, vì ứng dụng sở hữu cơ sở dữ liệu và cả hai nên đồng bộ hóa càng nhiều càng tốt. Ví dụ với việc đặt tên bảng / lớp và trường / cột. Ngoài ra, cách tiếp cận để cho các DBA viết các thủ tục có mùi giống như các silo phát triển, thay vì có một nhóm đa ngành.
Augusto

7
Các SP không nhất thiết phải luôn hiệu quả hơn và tôi nghĩ rằng việc chuyển SQL cho các DBA là một cách tồi tệ. Là một chuyên gia về miền, nhà phát triển nên biết họ muốn lấy dữ liệu nào và làm thế nào để có được nó
Martijn Verburg

1
Đây là một câu trả lời tốt, nhưng theo kinh nghiệm của tôi, hầu hết khách hàng thực sự không cần tăng hiệu suất để kiểm soát truy cập dữ liệu thông qua các thủ tục được lưu trữ so với sự bất tiện khi sử dụng đầy đủ các công cụ ORM của bạn trên lớp ứng dụng. Thường xuyên hơn không, tôi thấy những quyết định kiến ​​trúc này được đưa ra trong các cửa hàng phần mềm nơi họ có nhu cầu biện minh cho mức lương cồng kềnh của các lập trình viên thủ tục lưu trữ "râu xám" không có kỹ năng nào khác.
maple_shaft

1
@Augusto the approach of letting the DBAs write the procedures smells like development silos+100 internets cho bạn về viên ngọc thật này. Tôi luôn thấy đây là trường hợp truy cập dữ liệu được kiểm soát thông qua các thủ tục được lưu trữ.
maple_shaft

1
@maple_shaft: tại sao, không phải các DBA viết SP được coi là một phần của nhóm nhà phát triển? Ở nơi nó hoạt động, họ là những lập trình viên chuyên nghiệp, những người biết rõ khía cạnh này của hệ thống, tốt hơn nhiều so với hầu hết các nhà phát triển có mục đích chung. Đây có thể là vấn đề làm tăng sự phổ biến của ORM. Ý tôi là, không ai sẽ nghĩ hai lần về việc một nhà thiết kế làm GUI, vậy tại sao sự ghét bỏ đối với một kiến ​​trúc sư dữ liệu làm lược đồ?
gbjbaanb

2

Điều thường xảy ra là các nhà phát triển sử dụng không chính xác các đối tượng ORM của họ làm mô hình miền.

Điều này không chính xác và liên kết miền của bạn trực tiếp với lược đồ DB của bạn.

Điều thực sự cần có là các mô hình miền riêng biệt phong phú như bạn muốn và sử dụng lớp ORM một cách riêng biệt.

Điều này có nghĩa là bạn sẽ cần ánh xạ giữa mỗi bộ đối tượng.


1
Đây là một ý tưởng tốt nhưng đối với các dự án nhỏ hơn, nó thực sự bắt đầu cảm thấy như quá mức cần thiết. Cách tiếp cận này cũng yêu cầu một lớp dịch giữa lớp kiên trì ORM và mô hình miền.
maple_shaft

@maple_shaft đã đồng ý và đó là ý của tôi khi "lập bản đồ" :-)
ozz

@Ozz, cách tôi đã làm việc chính xác là như vậy, các lớp thực thể LÀ mô hình miền (và tôi có thể thêm vào với khá nhiều thành công). Tôi đồng ý rằng nó liên kết mô hình miền với lược đồ, nhưng đó chính xác là những gì tôi muốn, vì tôi sử dụng quy ước về cấu hình và hiệu quả phụ là nếu tôi thấy một trường trên một thực thể, tôi không cần phải suy nghĩ nhiều về tên của bảng và cột nơi lưu trữ thông tin đó.
Augusto

@Augusto Tôi cũng đã làm nó! và như maple_shaft nói, thật tốt cho các ứng dụng kiểu CRUD nhỏ, nhưng có nhiều vấn đề khi OP đang tìm hiểu. Một ví dụ có thể là nơi bạn có nhiều bảng ánh xạ, ví dụ: StudentClass, ánh xạ Học sinh đến các lớp của chúng và chỉ chứa StudentID và classID, bạn không nhất thiết muốn ánh xạ này trong miền của mình. Đó chỉ là một ví dụ nhanh chóng trên đầu của tôi.
ozz

2
@Ozz: Nhận xét của bạn dường như mâu thuẫn với chính ý tưởng về ORM. Một ORM không "buộc miền của bạn trực tiếp vào lược đồ DB". ORM ánh xạ miền của bạn vào một lược đồ DB, mà không cần một lớp DAO riêng. Đó là toàn bộ quan điểm của một ORM. Và hầu hết các ORM đều xử lý ánh xạ nhiều đến nhiều, chỉ cần không có mô hình miền cần thiết cho bảng ánh xạ.
kevin cline

1

Các đối tượng miền của bạn có thể được điền tuy nhiên bạn vui lòng, không cần thiết phải sử dụng Hibernate. Tôi nghĩ thuật ngữ thích hợp là ánh xạ dữ liệu . Rất có thể dữ liệu bền bỉ của bạn sẽ có cấu trúc hoàn toàn khác với các đối tượng miền của bạn.


Chúng tôi hiện đang sử dụng trình ánh xạ dữ liệu, nhưng vấn đề là các procs được lưu trữ trả về một bộ dữ liệu tối thiểu, đôi khi không đủ để lấp đầy một đối tượng (có lẽ chúng ta nên cho phép các thủ tục được lưu trữ trả lại nhiều thông tin hơn). Ví dụ: một cửa hàng Proc có thể trả về email người dùng, tên, họ; trong khi một số khác thêm userid và một địa chỉ. Vì dữ liệu là khác nhau, chúng tôi sử dụng các đối tượng khác nhau để lưu trữ dữ liệu, điều đó có nghĩa là chúng tôi có các lớp 'Người dùng' khác nhau. Tôi đang cố gắng tránh sử dụng quyền thừa kế ở đây, vì tôi nghĩ đó là việc sử dụng sai.
Augusto

@Augusto: Giao diện?
Kramii phục hồi Monica

@Karmii, tôi không nghĩ các giao diện trợ giúp ở đây, vì khi đó chúng ta sẽ cần sao chép logic trong các lớp khác nhau. Hoặc chúng ta có thể sử dụng các giao diện và sau đó ủy quyền xử lý cho lớp người trợ giúp, nhưng đó không thực sự là OO :(.
Augusto

1
@Augusto Tôi không hiểu vấn đề: "các procs được lưu trữ trả về một tập hợp dữ liệu tối thiểu, đôi khi không đủ để lấp đầy một đối tượng" Vì vậy, bạn thay đổi sproc hoặc tạo một cái khác, sau đó để trình ánh xạ dữ liệu thực hiện ánh xạ
NimChimpsky
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.