thảo luận [Thảo luận] Repository Pattern là cái bullsh*t nhất khi đã có ORM framework?

Có nên sử dụng repository pattern khi đã có ORM framework rồi ko?

  • Có - có lợi nhiều lắm để tôi cmt bên dưới

    Votes: 29 19.2%
  • Có - thấy người ta hay xài thì mình xài thôi (chắc là cũng có lợi gì đó nhưng dek biết)

    Votes: 25 16.6%
  • Không - tốn công vô ích, đẽ ra cho thêm việc phức tạp chứ ko lợi lộc gì đáng kể

    Votes: 19 12.6%
  • Không - code nhiều mệt vãi, xài trực tiếp ORM cho nhanh (cũng ko biết là có lợi hay ko)

    Votes: 21 13.9%
  • Tuỳ - tuỳ dự án, tuỳ yêu cầu

    Votes: 57 37.7%

  • Total voters
    151
Cái này dùng cho mục đích DI mà theo Mic theo hướng đó và cũng theo strategy design pattern. Em hiểu được như vậy. Bộ khung của cái này bao gồm Bussiness Layer( Service), Data Access Layer. Nó là tách biệt dễ maintain.
 
Last edited:
ủa tưởng bàn ORM mà cuối cùng chỉ gói gọn EF thui hả?

Ai cấm a bàn cái khác đâu. C# có EF, Java có Hibernate rồi đấy.

Giờ hóng các anh làm Golang, Python, PHP… vào đi tôi tiếp hết :shame:

Những gì tôi nói ở EF, .Net đều có cái tương đương cho các tech stack khác. Vấn đề các a có thấy dc sự trừu tượng hoá của nó rồi tìm ra cái tương đương bên tech stack của a ko thôi. :canny:

via theNEXTvoz for iPhone
 
Anh Ếch cứ chửi vì bài toàn của ảnh ko cần Repository, còn của người khác lại cần. Dù EF nó implement sẵn nhưng đôi khi tự build cái Repository khác wrap ngoài lại dễ làm thêm những cái khác. Đơn giản như dự án của tôi, ở phần Repository các query của bọn tôi cần build thêm 1 số default param, và nó centralize ở cái repo đó thôi, ko muốn phải viết lại ở đống service. Hơn nữa nó liên quan đến bài toàn caching, cái Cache provider của của thằng EF nó ko đáp ứng dc, nên chúng tôi xử lý cache luôn ở Repository. Những thứ này có thể xử lý trong cái DbContext, nhưng nó phức tạp hơn việc bọn tôi xử lý ở thằng Repo
Mặt khác chúng tôi cũng ko muốn ở phía service nó access vào cái DbContext. Tôi đọc cái đoạn anh bảo review code để cấm dev làm cái này, tôi cười vl. Như anh gì trên kia bảo, thế cần đéo access modifier, cần đéo gì interface contract.
Anh cứ nhìn qua cái giếng của anh, thì anh còn thấy nhiều cái thối nữa
 
Anh Ếch cứ chửi vì bài toàn của ảnh ko cần Repository, còn của người khác lại cần. Dù EF nó implement sẵn nhưng đôi khi tự build cái Repository khác wrap ngoài lại dễ làm thêm những cái khác. Đơn giản như dự án của tôi, ở phần Repository các query của bọn tôi cần build thêm 1 số default param, và nó centralize ở cái repo đó thôi, ko muốn phải viết lại ở đống service. Hơn nữa nó liên quan đến bài toàn caching, cái Cache provider của của thằng EF nó ko đáp ứng dc, nên chúng tôi xử lý cache luôn ở Repository. Những thứ này có thể xử lý trong cái DbContext, nhưng nó phức tạp hơn việc bọn tôi xử lý ở thằng Repo
Mặt khác chúng tôi cũng ko muốn ở phía service nó access vào cái DbContext. Tôi đọc cái đoạn anh bảo review code để cấm dev làm cái này, tôi cười vl. Như anh gì trên kia bảo, thế cần đéo access modifier, cần đéo gì interface contract.
Anh cứ nhìn qua cái giếng của anh, thì anh còn thấy nhiều cái thối nữa

Nhiều khi các anh cũng nên nhìn xuống giếng xem nó có con ếch ở đó ấy
BdgiW7R.png


Anyway, tôi chỉ phản đối vụ Generic Repository implement sai đi public cái IQueryable ra thôi. Còn giờ tôi lượn đây. :go:
 
Các anh còn trẻ nên khi các anh bắt đầu code, các anh tiếp cận với EF và vì thằng EF nó làm việc theo cách của nó như các anh đang thấy. Và các anh nghĩ nó là cả thế giới.

Rồi các anh quay lại chửi Repository Pattern như các hàm GetById, GetByName là ko cần thiết. Các anh đang bắn đại bác vào lịch sử phát triển phần mềm với tri kiến của các anh đấy.

Tui đã đưa ví dụ với NHibernate Session rồi. Các anh muốn biết thì thử học nó đi. Khi các anh làm việc với NHibernate Session thì các anh mới hiểu thế nào là Unit Of Work.

Và vì là Unit Of Work nên cần các hàm GetById để gói gọn và chấm dứt
Session/Transaction trong một Unit Of Work để nó không ảnh hưởng đến các tác vụ khác.

Tui ko phải chuyên gia Ef, nhưng hồi còn làm NHibernate thì trong 1 UnitOfWork tôi có thể gởi đồng thời nhiều query lên server cùng một thời điểm để tránh round trip rất hay. Mà giờ già rồi ko nhớ nó gọi là gì.

Và đó là cách làm việc của các ORM thời đó. (Và bây giờ?)
. Cho tới khi thằng EF ra đời. Nó hoạt động theo một cách hoàn toàn khác để tracking changes của Entity và loại bỏ khái niệm Session (hoặc nó có internal Session tui ko rành) nên Unit Of Work nó ko có ý nghĩa trong EF.

Một cái khác biệt lớn nhất khi làm việc với Ef là Repository không khởi tạo Singleton được. Trong khi NHibernate thì tạo Singleton Repository bình thường.

Các anh em làm Python, Php,... có thể chia sẻ Orm bên các ngôn ngữ đó hoạt động như thế nào? Nhưng tui đoán các anh em vẫn sẽ cần Repository Pattern với GetById hay GetByName.

Edit: Định trả lời anh Ếch ở dưới mà nghĩ. Đọc tới dòng addscoped inject vào singleton instance, tôi lắc đầu. Chắc hi vọng nó sẽ tự tạo instance mới của DbContext bằng phép màu. Rồi multi-theading kiểu gì, muli-user, parallel editing kiểu gì. Thôi tốn thời gian vô ích nên tui out topic. Bye bye anh em.

Anh ignore ếch xanh xong vào comment với các ae khác thôi.
 
Anh Ếch cứ chửi vì bài toàn của ảnh ko cần Repository, còn của người khác lại cần. Dù EF nó implement sẵn nhưng đôi khi tự build cái Repository khác wrap ngoài lại dễ làm thêm những cái khác. Đơn giản như dự án của tôi, ở phần Repository các query của bọn tôi cần build thêm 1 số default param, và nó centralize ở cái repo đó thôi, ko muốn phải viết lại ở đống service. Hơn nữa nó liên quan đến bài toàn caching, cái Cache provider của của thằng EF nó ko đáp ứng dc, nên chúng tôi xử lý cache luôn ở Repository. Những thứ này có thể xử lý trong cái DbContext, nhưng nó phức tạp hơn việc bọn tôi xử lý ở thằng Repo
Mặt khác chúng tôi cũng ko muốn ở phía service nó access vào cái DbContext. Tôi đọc cái đoạn anh bảo review code để cấm dev làm cái này, tôi cười vl. Như anh gì trên kia bảo, thế cần đéo access modifier, cần đéo gì interface contract.
Anh cứ nhìn qua cái giếng của anh, thì anh còn thấy nhiều cái thối nữa
Bác nói chuẩn, một số bác chưa hiểu đúng về repo nên cãi cùn, các bác nào chưa hiểu đúng thì làm ơn ngồi đó nghe giải thích hoặc lên youtube coi nhé. Chứ đừng vác orm mang ra so sánh với repo design pattern.
 
Nhiều khi các anh cũng nên nhìn xuống giếng xem nó có con ếch ở đó ấy
BdgiW7R.png


Anyway, tôi chỉ phản đối vụ Generic Repository implement sai đi public cái IQueryable ra thôi. Còn giờ tôi lượn đây. :go:
Microsoft cũng nói return IQueryable phá vỡ cấu trúc Repo.
A key point to note is that our GetAllBlogs method returns IEnumerable<Blog>, and not IQueryable<Blog>. Returning the latter would mean that query operators can still be composed over the result, requiring that EF Core still be involved in translating the query; this would defeat the purpose of having a repository in the first place

https://docs.microsoft.com/en-us/ef/core/testing/testing-without-the-database

Ngoài ra mình cũng hỏi là trong t/h dùng repo, nếu câu query mình muốn select field cần thiết, ko select all domain thì phải làm sao.
Thanks
 
Last edited:
Tôi hiểu cái mô hình của a đang là như này:
Controllers -> Services -> Repositories -> ORM

Còn theo tôi nó nên là như này:
Controllers -> Services -> ORM

Lý do tôi chửi là vì tôi thấy rất nhiều dự án đã xài ORM rồi còn chèn thêm thằng Repositories bên trên như anh với rất nhiều lý do mơ hồ đưa ra nhưng khi tôi xoáy vào cụ thể vì sao mô hình phía dưới ko đáp ứng đc thì chẳng ai trả lời dc.

Khi nào rảnh thì a demo 1 phát cho tôi mở mang tầm mắt chứ gặp Vozer ngoài đời ngại lắm, ko dám gặp đâu. :canny:
bác thớt cho mình hỏi, vd trong case này khi áp dụng cho Laravel:
Controllers -> Services -> ORM
Mình có thể dùng trực tiếp ORM trong Controller hay ko ? hay bắt buộc phải đưa nó vào Services. Mình hiểu Service là nơi chưa business logic của application, nhưng nếu chức năng chỉ đơn giản như hiển thị danh sách users(getListUsers()) thì nên dùng trực tiếp ở Controllers hay viết trong Services ? :adore: Tương tự, nếu mình có thêm 1 chức năng dạng như send email, trong Laravel thường thì sẽ tạo SendEmailJob class để đưa vào queue. Nếu áp dụng pattern trên thì chẳng hạn trong SendEmailJop cần tương tác vs ORM để lấy data thì cũng call Services -> ORm hay dụng trực tiếp ORM trong đó luôn ạ :sweet_kiss:
 
bác thớt cho mình hỏi, vd trong case này khi áp dụng cho Laravel:
Controllers -> Services -> ORM
Mình có thể dùng trực tiếp ORM trong Controller hay ko ? hay bắt buộc phải đưa nó vào Services. Mình hiểu Service là nơi chưa business logic của application, nhưng nếu chức năng chỉ đơn giản như hiển thị danh sách users(getListUsers()) thì nên dùng trực tiếp ở Controllers hay viết trong Services ? :adore: Tương tự, nếu mình có thêm 1 chức năng dạng như send email, trong Laravel thường thì sẽ tạo SendEmailJob class để đưa vào queue. Nếu áp dụng pattern trên thì chẳng hạn trong SendEmailJop cần tương tác vs ORM để lấy data thì cũng call Services -> ORm hay dụng trực tiếp ORM trong đó luôn ạ :sweet_kiss:

Nên đưa vào services, tất nhiên nếu muốn code 1 layer, xài trực tiếp trên controllers thì cũng được nhưng làm dạng chơi chơi chứ project thực tế ko khuyến khích.

Nên tách biệt 2 phần là presentation và logic ra để có gì unit test cả 2, hoặc đổi tầng presentation thì service vẫn ko đổi vì dù sao service mới là core của application.
 
Nên đưa vào services, tất nhiên nếu muốn code 1 layer, xài trực tiếp trên controllers thì cũng được nhưng làm dạng chơi chơi chứ project thực tế ko khuyến khích.

Nên tách biệt 2 phần là presentation và logic ra để có gì unit test cả 2, hoặc đổi tầng presentation thì service vẫn ko đổi vì dù sao service mới là core của application.
Vậy trong trường hợp 2 Service cần dùng chung 1 method thì sao nhỉ ? vd trong PostService cần lấy danh sách users. Trong UserService đã có sẵn hàm getListUsers(). Trong trường hợp này mình nên handle ntn ạ ? Trong PostService, gọi UserService->getListUsers() ? hay lại tách nó ra thêm 1 class khác(Helpers) ? :sweat:
 
Vậy trong trường hợp 2 Service cần dùng chung 1 method thì sao nhỉ ? vd trong PostService cần lấy danh sách users. Trong UserService đã có sẵn hàm getListUsers(). Trong trường hợp này mình nên handle ntn ạ ? Trong PostService, gọi UserService->getListUsers() ? hay lại tách nó ra thêm 1 class khác(Helpers) ? :sweat:

Trường hợp này có 3 cách:
1. Là dùng 3 layers, dùng Repository (DDD) để gom cái logic đó xài chung cho nhiều services
2. Tạo extension methods, helper hay cái gì đó tương tự C# cho bên PHP.
3. Gọi cross-services, service call service. Cách này thì phải chú ý chổ quản lý transaction để đảm bảo sopce của nó đúng như mong đợi vì nó gọi lồng nhau

Chọn cách nào là tuỳ vào implement hiện tại của dự án.
 
Microsoft cũng nói return IQueryable phá vỡ cấu trúc Repo.
A key point to note is that our GetAllBlogs method returns IEnumerable<Blog>, and not IQueryable<Blog>. Returning the latter would mean that query operators can still be composed over the result, requiring that EF Core still be involved in translating the query; this would defeat the purpose of having a repository in the first place

https://docs.microsoft.com/en-us/ef/core/testing/testing-without-the-database

Ngoài ra mình cũng hỏi là trong t/h dùng repo, nếu câu query mình muốn select field cần thiết, ko select all domain thì phải làm sao.
Thanks
Có ai giải quyết dc T/H này của mình ko, mình chỉ muốn select các fields cần thiết ( select loading) để đảm bảo perf nhưng repo partern chỉ nên trả về nguyên cái domain class chứ ko phải DTO.
Làm sao ko phá vỡ patern mà vẫn thỏa mãn yêu cầu của mình vậy.
 
em đã gặp 1 cái project dùng repository pattern, nhưng kiểu nửa mùa. Dùng repository nhưng vẫn dùng orm tạo query ở service, thậm chí là cả controller (kiểu code tùy hứng, thích thì dùng orm, thích thì dùng repo). Code cái project này khó chịu vcc.
 
Thì gọi cross service bình thường chứ có gì đâu
Vậy thì sẽ gặp trường hợp các services bị lồng nhau:( mình chưa gặp trường hợp này bao giờ, nhưng nghe nói là nên tránh :ah:
Trường hợp này có 3 cách:
1. Là dùng 3 layers, dùng Repository (DDD) để gom cái logic đó xài chung cho nhiều services
2. Tạo extension methods, helper hay cái gì đó tương tự C# cho bên PHP.
3. Gọi cross-services, service call service. Cách này thì phải chú ý chổ quản lý transaction để đảm bảo sopce của nó đúng như mong đợi vì nó gọi lồng nhau

Chọn cách nào là tuỳ vào implement hiện tại của dự án.
Bác có thể nói thêm 1 xíu về vấn đề này được không :love:
Cách này thì phải chú ý chổ quản lý transaction để đảm bảo sopce của nó đúng như mong đợi vì nó gọi lồng nhau :love:
 
Có ai giải quyết dc T/H này của mình ko, mình chỉ muốn select các fields cần thiết ( select loading) để đảm bảo perf nhưng repo partern chỉ nên trả về nguyên cái domain class chứ ko phải DTO.
Làm sao ko phá vỡ patern mà vẫn thỏa mãn yêu cầu của mình vậy.

Ai nói repo pattern chỉ nên trả về nguyên cái domain class. A muốn projection bao nhiêu fields thì cứ việc select đúng fields ở dưới thôi. Nhìn từ thằng services nó chỉ xem như domain object, có thể full fields hoặc ít fields tuỳ vào business rules.

Chính vì lẽ đó nên đa số các Generic Repository support full fields entity và các hàm rất cơ bản thì cũng ít được sử dụng, code nhiều mà xài ko bao nhiêu. Cùng lắm xài được cái hàm GetById, GetbyName

"The more code is reusable is the more code is not usable"
 
Back
Top