Minimalist Forum Reader
Theo e thấy thì cả bác Frog và các bác kia đều có ý đúng, nhưng em bổ sung thêm 1 góc nhìn support cho việc dùng repository pattern khi dự án dùng ORM là layer Repository mang lại lợi ích trong việc đóng vai trò là 1 layer bọc bussinesslogic.

HIểu đơn giản là ORM bọc technical, còn Repo bọc nghiệp vụ. Rõ ràng nếu là 1 SA hay dev bác không muốn đem cục này ở khắp nơi
_dbContext.Invoices
.Where(x => x.TaxEntityId == taxEntityId
&& x.Status != 1
&& x.IssueDate >= from
&& x.IssueDate <= to);

Thay vì chỉ cần

invoiceRepository.GetInvoicesInPeriod();
1 cái expose Iqueryable<> còn 1 cái expose business intent. Với 1 dự án chỉ crud vài chục bảng thì không sao nhưng nếu dự án có nghiệp vụ phức tạp chút theo em là khác biệt rõ ràng đấy.

Chưa kể việc mock _dbContext để unitest cũng có cả tỷ vấn đề khi mock các dbset và return iqueryable<>, trong khi cái em cần ở unit test là test business logic, em chỉ cần mock result cho repository là được.

CHung quy lại thì pattern nào cũng có ưu nhược điểm và luôn phải trade-off thôi. Không có đúng sai mà chỉ có phù hợp hay không thôi.
Reactions: tonghoangvu
còn 1 use case nữa là khi DB setup phức tạp, như sharding, partition và muốn abstract khỏi business logic :D
Reactions: Mỹ Chu Lang
Theo e thấy thì cả bác Frog và các bác kia đều có ý đúng, nhưng em bổ sung thêm 1 góc nhìn support cho việc dùng repository pattern khi dự án dùng ORM là layer Repository mang lại lợi ích trong việc đóng vai trò là 1 layer bọc bussinesslogic.

HIểu đơn giản là ORM bọc technical, còn Repo bọc nghiệp vụ. Rõ ràng nếu là 1 SA hay dev bác không muốn đem cục này ở khắp nơi

1 cái expose Iqueryable<> còn 1 cái expose business intent. Với 1 dự án chỉ crud vài chục bảng thì không sao nhưng nếu dự án có nghiệp vụ phức tạp chút theo em là khác biệt rõ ràng đấy.

Chưa kể việc mock _dbContext để unitest cũng có cả tỷ vấn đề khi mock các dbset và return iqueryable<>, trong khi cái em cần ở unit test là test business logic, em chỉ cần mock result cho repository là được.

CHung quy lại thì pattern nào cũng có ưu nhược điểm và luôn phải trade-off thôi. Không có đúng sai mà chỉ có phù hợp hay không thôi.
invoiceRepository.GetInvoicesInPeriod();
Repository thuộc infrastructure layer thì sao lại chứa GetInvoicesInPeriod() thuộc về domain được bác.

invoiceDomain.GetInvoicesInPeriod(); thì nó sẽ rõ ràng hơn. Giả sử GetInvoicesInPeriod là nghiệp vụ mà lại nằm trong repo thì invoiceDomain đang không mô tả đầy đủ business logic của nó và
GetInvoicesInPeriod() đang nằm ở vùng xám của Domain layer và Infrastructure layer
Như e đang làm có case này do thiết kế db lỏ mà ko dùng repository code nó dài ngoằng. Giả sử có bảng Category chứa các record cũng như các version của nó trong đó. Muốn lấy ra version hiện tại của 1 record nào phải viết đoạn query khá dài vì phải join do .net cũ quá ko xài đc window function. Giờ đoạn ấy ko viết 1 hàm trong repo rồi dùng lại mà đẩy code lên chỗ services chắc e xỉu mất
Keaa7zY.gif
Reactions: GeniVN
invoiceRepository.GetInvoicesInPeriod();
Repository thuộc infrastructure layer thì sao lại chứa GetInvoicesInPeriod() thuộc về domain được bác.

invoiceDomain.GetInvoicesInPeriod(); thì nó sẽ rõ ràng hơn. Giả sử GetInvoicesInPeriod là nghiệp vụ mà lại nằm trong repo thì invoiceDomain đang không mô tả đầy đủ business logic của nó và
GetInvoicesInPeriod() đang nằm ở vùng xám của Domain layer và Infrastructure layer
fen cứ nghĩ đơn giản thôi. Repository là 1 nơi chứa query thuộc cái domain fen đang code. Invoices thì InvoiceRepository để câu GetInvoicesInPeriod là chuẩn rồi. Giả sử GetInvoicesInPeriod có thể cache được, hay phải query trên nhiều partition, shard, etc. thì nó phải nằm ở Repository để những thằng Service khác dùng được chứ k để chung, chạy thẳng DbContext hay ORM gì đó được, thế thì cái service nó bát nháo cực kỳ

fen cứ nghĩ Repository là lớp truy vấn dữ liệu của 1 domain cụ thể thì cái ý của fen trên make sense liền
Reactions: andinhtien, tonghoangvu and 1457040007
Như e đang làm có case này do thiết kế db lỏ mà ko dùng repository code nó dài ngoằng. Giả sử có bảng Category chứa các record cũng như các version của nó trong đó. Muốn lấy ra version hiện tại của 1 record nào phải viết đoạn query khá dài vì phải join do .net cũ quá ko xài đc window function. Giờ đoạn ấy ko viết 1 hàm trong repo rồi dùng lại mà đẩy code lên chỗ services chắc e xỉu mất
Keaa7zY.gif
viết trong service luôn, wrap toàn bộ query trong private method của service class là được mà. :rolleyes:
viết trong service luôn, wrap toàn bộ query trong private method của service class là được mà. :rolleyes:
vậy thì nó lại khó test. Fen xài mock db hay testcontainer dc thì k nói :D
Reactions: Mỹ Chu Lang
viết trong service luôn, wrap toàn bộ query trong private method của service class là được mà. :rolleyes:
Case của e nó giống như bác GeniVN nói ở trên đó, dùng nhiều service nên viết vào repo gọn hơn
KxSw50A.png
1. RP nó sinh ra méo phải cho việc đổi db
2. Chuyện đổi db là hoàn toàn có thể xảy ra, tất nhiên k phsir biến. Ví dụ dùng oracle xong sau nhiều năm tốn tiền quá -> move sang postgres, đổi 1 phần relation db sang nosql…
3. Mục đích chính của RP nó là tập trung domain logic lại 1 chỗ, tách domain service ra khỏi persistance,
4. Code lặp lại những gì ORM đã làm như get, getAll, save, update -> đây là do bad implement chứ k phải do bản thân RP
5. Quản lý transaction nên đc thực hiện ở tầng service, nếu ném vào repository thì là bad practice cmnr
Thôi ngại type tiếp quá, nhưng mà đây cũng là những cái ngày xưa tôi nghĩ về RP mà sau này lên SA mới clear hết đc :sad:


via theNEXTvoz for iPhone
bac co the share mot vai repo implement ngon dc k bac
tôi add thêm rồi đó. Nói chung đây là 1 kiểu như insurance cho các thay đổi trong tương lai ấy. Có thể bây giờ anh thấy bullshit nhưng 5 năm 10 năm mấy thằng khác vật vã thì anh phẻ re. Có lẽ người ta ko biết tương lai nó thay đổi yêu cầu gì, nên xài cái generic nhất để đón đầu thoy
pzGVwuf.png


ví dụ anh viết sql cho mysql only, thằng lead đòi orm cho mọi loại sql, anh chửi vẽ chuyện, nhưng tương lai 10 năm nữa oracle nó giết mysql lại phải đổi sang postgres thì sao, orm nó đỡ cho anh hết. Lúc thay đổi đó anh ko phải chuyển code mysql trong 10 năm đó thành code postgresql. Cái repo pattern này có lẽ tương tự.
Bác tiên đoán cũng ghê đấy thằng oracle sút nguyên team code mysql rồi
Reactions: Mỹ Chu Lang
Lần cuối các bác thực sự đổi database là khi nào vậy (ví dụ case simple nhất từ Postgres sáng MySQL), tôi thì chưa gặp nên chưa có kn.
Reactions: Mỹ Chu Lang
Theo e thấy thì cả bác Frog và các bác kia đều có ý đúng, nhưng em bổ sung thêm 1 góc nhìn support cho việc dùng repository pattern khi dự án dùng ORM là layer Repository mang lại lợi ích trong việc đóng vai trò là 1 layer bọc bussinesslogic.

HIểu đơn giản là ORM bọc technical, còn Repo bọc nghiệp vụ. Rõ ràng nếu là 1 SA hay dev bác không muốn đem cục này ở khắp nơi

1 cái expose Iqueryable<> còn 1 cái expose business intent. Với 1 dự án chỉ crud vài chục bảng thì không sao nhưng nếu dự án có nghiệp vụ phức tạp chút theo em là khác biệt rõ ràng đấy.

Chưa kể việc mock _dbContext để unitest cũng có cả tỷ vấn đề khi mock các dbset và return iqueryable<>, trong khi cái em cần ở unit test là test business logic, em chỉ cần mock result cho repository là được.

CHung quy lại thì pattern nào cũng có ưu nhược điểm và luôn phải trade-off thôi. Không có đúng sai mà chỉ có phù hợp hay không thôi.
Nếu ko muốn đẩy 1 cục đi khắp nơi thì mình có thể cho xuống Application layer mà gọi. Và nếu Repo chỉ để bọc business logic, thì nói thật là chẳng cần nó cũng có thể làm được, quan trọng người code là ai.

Về việc test, mình nghĩ quan trọng là cách bạn xây dựng hệ thống test thế nào. Như cá nhân mình, nếu đã dùng ORM thì build thêm luôn InMemory hoặc SQLite Database local trên môi trường Dev cho việc test, và mình thấy test còn nhanh và tiện hơn nhiều. Vì mình chỉ việc đẩy vào raw data là test được ngay, chứ bạn Mock thì cái input cần để test nó là processed data rồi, cho nên ko nhanh được, ko cẩn thận vớ vẩn data để test còn sai nữa ấy chứ.