thảo luận Vấn đề về separate Repository/Service/Controller

  • Người tạo chủ đề Người tạo chủ đề soledad86
  • Ngày bắt đầu Ngày bắt đầu
Tôi chửi việc anh đưa luận điểm không đủ chặt chẽ.
Tôi chém gió chứ có phải bảo vệ luận văn đâu mà anh kêu tôi đưa luận điểm với bench test. Mấy anh làm quá.

À chửi thêm cái nosql nữa.
Tôi có nói gì về nosql đâu nhỉ? Tôi chỉ nói nhiều khi do politics trong công ty chef mới lên muốn có nguồn gió mới đổi sql thành nosql mặc dù sql nó chả có vấn đề gì thì sao lại chửi tôi nhỉ? Hay anh chửi lộn tôi với ai thế.
 
Anh @lam vung lau lam đã out topic rồi làm tôi không được học thêm cái gì mới.

Bàn về con người.
Ở trên các bạn nói abstract thinking hay abstraction thì đúng chuyên môn và hàn lâm quá rồi. Tôi thì chỉ có một cái giải thích thôi đó là vì tôi lười. Tôi lười phải chạy theo các thay đổi của tụi bên Business và cả theo chef tổng nên tôi phải làm sao mà khi có những thay đổi diễn ra, tôi phải không bị stress khi sửa các thay đổi đó vào.

Sẽ có những thời khắc mà các quyết định nó hoàn toàn mang tính "chính trị" chứ chẳng phải gì về công nghệ cái con mịa gì cả. Ví dụ đang local chạy tốt việc gì phải lên cloud, đang SQL tốt việc gì phải qua NoSQL. Đó là vì nỗi sợ của những người không hiểu. Họ sợ bị tụt hậu, họ sợ bị bỏ lỡ. Mà những người đó toàn là CEO, Chủ tịch quản trị, CIO thôi, toàn dân Politics cả chứ nền tảng technical được bao nhiêu so với dân chuyên môn. Nhưng đó là cách thế giới vận hành và phát triển.

Bàn về tech.

1.
Giờ ai nói và về select field nhanh hơn với select star thì thôi mấy anh tự làm cái test đi. Mấy anh lựa cái bảng nào nhiều dòng nhất mà mấy anh có làm cái SQL "Select * from table where id =" với cái "Select id from table where id=" xem coi nó lệch bao nhiêu ms. Đấy là phần SQL.

Rồi về phần mapping giờ mấy anh tự code một cái function map giữa 2 object A và B (copy giá trị 1-1). Một cái map full 20 properties một cái map 1 property. Rồi mấy anh đo xem coi nó lệch bao nhiêu ms.

Sau khi làm xong mấy anh báo lại xem mấy anh tối ưu được bao nhiêu ms.

Tôi báo kết quả luôn là 0ms. Tức là về performance các anh lợi được là 0ms.
Nhưng cũng phải nói các anh tiết kiệm được vài kb bộ nhớ trong quá trình map đấy.

Rồi giờ các anh đứng trước quyết định là mấy anh làm spaghetti code để tiết kiệm vài kb bộ nhớ trong vài giây thì có đáng không?

2. Rồi thứ 2 là về Raw SQL.
- Các anh nói các anh thích viết raw sql. It's ok. Đó là sở thích của các anh. Nhưng đứng ở vị trí của tôi trước dự án 20-30 dev. Các anh kêu tôi dùng raw sql á? Một là các anh bị điên. Hai là các anh bị khùng. Ai sẽ quản lý nổi cái đống raw sql đó? Convention, SQL Function, SQL Injection... ai sẽ validate? Rồi khi thay đổi Business Logic dùng cột A thay cột B thì ai sẽ ngồi search và replace rồi test lại là mọi thứ đều đúng?

- Rồi các anh gào lên là cần Raw SQL để tạo report cho nó performance. Tôi đồng ý với các anh luôn. Nhưng quan trọng là các anh đặt cái Raw SQL đó ở đâu? Các anh sẽ tự hào quăng luôn câu SQL đó vào trong code của các anh. Và tôi chúc các anh maintain nó vui vẻ cả phần đời còn lại của các anh.
Với tôi, quy tắc quan trọng nhất khi dùng ORM đó là khi anh không thể dùng ORM để viết một câu SQL anh muốn thì câu SQL đó phải nằm ở Database Server chứ không phải ở code của anh. Bởi vì, rõ ràng câu SQL đó nó gắn với một loại Database nhất định chứ không còn abstract đủ để dùng ORM nữa. Khi để câu SQL đó trong code tức là anh đã tự bắn vào "chim" mình, sau này khi có thay đổi thì anh ăn đạn đừng kêu trách ai.

Thế thôi. Đó là ý của tôi. Tầm nhìn nó phụ thuộc vào vị trí các anh đứng. Luôn nhớ là như vậy.


phần 1: có người test rồi.

phần 2: ORM nó có nhiều tác dụng hơn vậy nhiều. Tất nhiên nó cũng có trade off, đó là performance. Cái anh đang nói thì chỉ cần query builder là đủ, tôi là dev trong 1 repo có 500 dev, vẫn đang dùng query builder thay vì ORM vì vấn đề performance.

phần 3: GetUserByID, không thể select theo từng field vì khi đó rất khó maintain, nhưng cũng ko thể select * nếu table quá lớn. Giải pháp tôi từng làm cho team đơn giản là tách theo từng cụm. Ví dụ GetAll -> UserEntity, GetCredential -> UserCredentialEntity, GetContact -> UserContactEntity, GetProfile -> UserProfileEntity. Nếu cần 2 loại entity sẽ GetAll. Tất nhiên nó ko tối ưu, nhưng nó sẽ cân bằng cho cả performance và maintainance.
 
Hơi specific tý nhưng chắc dự án bác theo backend Java Spring 5 webflux à :D
Mô hình MVC là kinh điển cho bên server side rồi, tuy nhiên nó không phải (không cần) lúc nào cũng vậy.
Có rất nhiều thứ phát sinh thêm mà ko biết rõ nó nằm ở layer nào, như kiểu Listener, Handler, Exception, Bus chẳng hạn
Còn việc các ông kia bảo gọi trực tiếp thì có thể là do đơn giản thôi, tuy nhiên em vẫn prefer việc đủ layer (controler -> service -> dao)
 
Tôi chém gió chứ có phải bảo vệ luận văn đâu mà anh kêu tôi đưa luận điểm với bench test. Mấy anh làm quá.


Tôi có nói gì về nosql đâu nhỉ? Tôi chỉ nói nhiều khi do politics trong công ty chef mới lên muốn có nguồn gió mới đổi sql thành nosql mặc dù sql nó chả có vấn đề gì thì sao lại chửi tôi nhỉ? Hay anh chửi lộn tôi với ai thế.

Hôm nay ngủ kém, có khi đọc nhầm.

Sent from HUAWEI COR-L29 using vozFApp
 
phần 3: GetUserByID, không thể select theo từng field vì khi đó rất khó maintain, nhưng cũng ko thể select * nếu table quá lớn. Giải pháp tôi từng làm cho team đơn giản là tách theo từng cụm. Ví dụ GetAll -> UserEntity, GetCredential -> UserCredentialEntity, GetContact -> UserContactEntity, GetProfile -> UserProfileEntity. Nếu cần 2 loại entity sẽ GetAll. Tất nhiên nó ko tối ưu, nhưng nó sẽ cân bằng cho cả performance và maintainance.

Đấy là ý tôi muốn trình bày. Cái chính là như anh trình bày, 1 cái GetUserById nó phân nhánh thành 4, 5 hàm như thế. Rồi mỗi khi có cái củ cải gì mới, thằng Dev nó lại định nghĩa một cái hàm mới . Đến cuối cùng nó là một đám hổ lốn chỉ để đưa về thông tin của một User. Mà đấy chỉ là cho 1 User thôi í, giờ chúng ta scale lên 10 Entities hay 100 Entities (như Order, Product, Role...) thì code nó phình ra tới mức nào nên tôi chỉ nói là tôi chọn hướng tối ưu theo cách nhìn của tôi chứ tôi không chọn theo hướng lợi thêm được vài giây (tôi không dám nói milli giây luôn vì sẽ có thằng nhảy vào chửi tiếp). Và bằng chứng là các hệ thống tôi chịu trách nhiệm vẫn vận hành tốt.

Tôi ví dụ một thằng tôi đã làm là ADAC ở Đức nhé. Đây là một dịch vụ khởi nguồn là dịch vụ kéo xe bị hư giữa đường và giờ nó thành một hệ thống khổng lồ bán đủ thứ trên đời trừ phim xxx. Tôi cũng chả bao giờ hỏi tới là có bao nhiêu request một ngày nên tôi không chắc về lượng request đâu nhưng tôi chỉ biết ở Đức thằng này là dịch vụ lớn duy nhất về mảng này.

90tr dân Đức hàng ngày lên đây mua sắm bảo hiểm, dịch vụ, gọi báo lỗi xe,... thì tôi nghĩ chắc cũng đông đông và nó chả có vấn đề mịa gì về performance cả.

Cả hệ thống đếch có tối ưu mịa gì với raw sql cả. Select fields thì có trong các trường hợp đặc biệt vì yêu cầu thôi (mà rất ít vì toàn đọc chủ yếu từ cache ra). Còn report thì những gì cần nhiều thời gian thì như tôi đã nói ở trên.

Các hệ thống nó tách biệt nhau ra, chạy trên các server khác nhau, thêm vào load balancer, cache system, replication tôi thật sự không hiểu mấy anh cứ khè mấy chục ms với tôi làm gì. Tôi đếch hiểu mấy hệ thống của các anh sao nó phải phụ thuộc quá nhiều vào Database server như thế.

Tôi thấy vấn đề nó chỉ nằm ở 20-30 dev tụi nó trình độ khác nhau. Quản mới là mệt, sẽ có 2,3 thằng nerd như các anh suốt ngày hò hét với tui về performance cũng có 2,3 thằng nó kệ mẹ cuộc đời check in vô phát sập mẹ luôn cái dev. Thế thôi.

phần 2: ORM nó có nhiều tác dụng hơn vậy nhiều. Tất nhiên nó cũng có trade off, đó là performance. Cái anh đang nói thì chỉ cần query builder là đủ, tôi là dev trong 1 repo có 500 dev, vẫn đang dùng query builder thay vì ORM vì vấn đề performance.
Tôi đồng ý khi cần nhanh, rất nhanh thì tối ưu hết tất cả và dùng raw sql là cần thiết như tôi đã ghi ở trên. Và thật sự tôi cũng không may mắn dẫn được đội 500 dev nên cũng không biết nó khủng cỡ nào. Bạn thật quá hạnh phúc.
 
@gaveezy: Rồi cám ơn bạn rất nhiều luôn. Như vậy tôi đã bị đập vào mặt là execution lệch 5ms và fetch time là 20ms. Như tôi chém gió là 0ms thì là "xạo lìn" (không phải tôi cố tình "xạo lìn" mà tôi test trên database tôi có đếch hiểu sao nó có 0ms (execution time) thôi. Tôi đã lựa cái bảng to nhất tôi có rồi).
Giờ tôi đợi tiếp anh @katoshi với anh @quandaso chứng minh tiếp là lệch khoảng bao nhiêu ms nũa.

Vậy đúng như ý tôi muốn hỏi và chứng minh giữa select * với select fied




@Edit: Tôi tìm ra lỗi của tôi rồi. Trên tool nó hiện 00:00:00 mà tôi đọc thành 00:00:00.0000. Xin lỗi anh em tức là có lệch vài ms. Nhưng tôi vẫn để bài viết như cũ không sửa nhé.
Z là có test của bác trên r tôi ko cần viết benchmark vs bàn cãi thêm j nữa nha.
Tôi chỉ ko đồng ý vụ anh nói select * vs select 1 column có perf như nhau thôi. Còn lại ko ý kiến j
 
Vài giây là sao, đối với tôi vài giây lệch là hệ thống treo cmnr, thậm chí response trả về > 100ms thôi đã là không được rồi. Khi hệ thống nó scale lên 15M/20M request trên ngày ông sẽ hiểu dù 20ms nó đã đáng giá như nào.
Tôi ko biết ông đã vận hành hệ thống bao giờ chưa, nếu chưa tôi quay lại cái video cho ông mở rộng tầm mắt, khi select * 1 triệu bản ghi và select id nó khác nhau nhiều như thế nào
Kết quả select * mất 48s, select id mất 1.6 giây tức là nhanh gấp 30 lần. Tận 30 lần đấy :D
Test như này k ổn đâu thím, Query lần 2 trên cùng 1 bảng thì đã có caching rồi. Thím test lại thử xem :D. Ngày xưa em nhớ xài oracle thì select * và select field hầu như không chênh lệch quá nhiều :D
@còn về ORM hay Raw SQL thì rõ ràng là ORM rồi, SQL chỉ viết khi thực sự cần tối ưu, dễ bảo trì bảo dưỡng, đỡ hỏng vặt, tưởng tượng 1 ngày công ty thím tuyển vài ba đứa newbie/junior, mà task yêu cầu viết 1 câu SQL hơi complex 1 tí thì tụi nó có mà ngồi đến năm sau cũng chưa viết ra đâu nhé :D :D :D
 
Sửa lần cuối:
T thấy 2 ông cãi ORM thật là hài. Cái gì cũng tùy trường hợp mà dùng. Đâu phải dự án nào rồi cũng 1M request, mà cũng đâu phải lúc scale sẽ giữ nguyên công nghệ đó. Dự án nhỏ, query đơn giản thì ORM với SQL raw vốn chả nhanh chậm hơn gì. Còn dự án lớn thì người tới time thì khi đó có xài ORM ko thì sẽ tính. 2 ông cãi có khác nào cãi cây cưa máy với cái dao thái cái nào hay hơn, tùy case cả.
Như thằng facebook xưa nó mới start nó còn dùng php load ì ạch kìa. Nay nó bự nó chuyển sang cái. 2 ông cãi tới năm sau cũng ko có kết qiar
 
Test như này k ổn đâu thím, Query lần 2 trên cùng 1 bảng thì đã có caching rồi. Thím test lại thử xem :D. Ngày xưa em nhớ xài oracle thì select * và select field hầu như không chênh lệch quá nhiều :D
@còn về ORM hay Raw SQL thì rõ ràng là ORM rồi, SQL chỉ viết khi thực sự cần tối ưu, dễ bảo trì bảo dưỡng, đỡ hỏng vặt, tưởng tượng 1 ngày công ty thím tuyển vài ba đứa newbie/junior, mà task yêu cầu viết 1 câu SQL hơi complex 1 tí thì tụi nó có mà ngồi đến năm sau cũng chưa viết ra đâu nhé :D :D :D
Select id nó là trường index, nên coi như nó cache sẵn rồi, đâu phải query trước rồi cái sau mới cache đâu bạn. Chính vì cache/index nó select ra mới nhanh, chứ select * bao gồm cả trường index cả trường không index thì cache lúc đấy ko hiệu quả nữa rồi. Thế mới nói select từng field nó tốt hơn, vì tận dụng đc index và cache của mysql. Hoặc là nếu trường nào cần select theo nhóm ví dụ phone,name thì đánh index theo 2 trường đó
1606748829512.png
Bạn nhìn thấy cột extra không
 

Tệp đính kèm

  • 1606748802878.png
    1606748802878.png
    13,3 KB · Lượt xem: 128
Sửa lần cuối:
Đấy là ý tôi muốn trình bày. Cái chính là như anh trình bày, 1 cái GetUserById nó phân nhánh thành 4, 5 hàm như thế. Rồi mỗi khi có cái củ cải gì mới, thằng Dev nó lại định nghĩa một cái hàm mới . Đến cuối cùng nó là một đám hổ lốn chỉ để đưa về thông tin của một User. Mà đấy chỉ là cho 1 User thôi í, giờ chúng ta scale lên 10 Entities hay 100 Entities (như Order, Product, Role...) thì code nó phình ra tới mức nào nên tôi chỉ nói là tôi chọn hướng tối ưu theo cách nhìn của tôi chứ tôi không chọn theo hướng lợi thêm được vài giây (tôi không dám nói milli giây luôn vì sẽ có thằng nhảy vào chửi tiếp). Và bằng chứng là các hệ thống tôi chịu trách nhiệm vẫn vận hành tốt.

Tôi ví dụ một thằng tôi đã làm là ADAC ở Đức nhé. Đây là một dịch vụ khởi nguồn là dịch vụ kéo xe bị hư giữa đường và giờ nó thành một hệ thống khổng lồ bán đủ thứ trên đời trừ phim xxx. Tôi cũng chả bao giờ hỏi tới là có bao nhiêu request một ngày nên tôi không chắc về lượng request đâu nhưng tôi chỉ biết ở Đức thằng này là dịch vụ lớn duy nhất về mảng này.

90tr dân Đức hàng ngày lên đây mua sắm bảo hiểm, dịch vụ, gọi báo lỗi xe,... thì tôi nghĩ chắc cũng đông đông và nó chả có vấn đề mịa gì về performance cả.

Cả hệ thống đếch có tối ưu mịa gì với raw sql cả. Select fields thì có trong các trường hợp đặc biệt vì yêu cầu thôi (mà rất ít vì toàn đọc chủ yếu từ cache ra). Còn report thì những gì cần nhiều thời gian thì như tôi đã nói ở trên.

Các hệ thống nó tách biệt nhau ra, chạy trên các server khác nhau, thêm vào load balancer, cache system, replication tôi thật sự không hiểu mấy anh cứ khè mấy chục ms với tôi làm gì. Tôi đếch hiểu mấy hệ thống của các anh sao nó phải phụ thuộc quá nhiều vào Database server như thế.

Tôi thấy vấn đề nó chỉ nằm ở 20-30 dev tụi nó trình độ khác nhau. Quản mới là mệt, sẽ có 2,3 thằng nerd như các anh suốt ngày hò hét với tui về performance cũng có 2,3 thằng nó kệ mẹ cuộc đời check in vô phát sập mẹ luôn cái dev. Thế thôi.


Tôi đồng ý khi cần nhanh, rất nhanh thì tối ưu hết tất cả và dùng raw sql là cần thiết như tôi đã ghi ở trên. Và thật sự tôi cũng không may mắn dẫn được đội 500 dev nên cũng không biết nó khủng cỡ nào. Bạn thật quá hạnh phúc.

scale lên thì phải phình lên đó là đương nhiên. Mình đc trả tiền để handle nó mà. Nếu việc dễ thì lấy đâu ra lương cao :)) Thật sự trong 1 database thì việc phải tách table ra nhiều entity cũng không thường xảy ra vì không nhiều table phải chia nhỏ như vậy, ngay trong ví dụ của anh thì Order và Role hoàn toàn có thể select *.

Thế nào là performance tệ nó tuỳ vào mỗi thằng, ví dụ hệ thống của anh là thương mại điện tử, ngay cả những trang khủng nhất VN như shopee lazada, 1s là chấp nhận đc. Nhưng nếu anh cung cấp api cho bên thứ 3 với số lượng rps lớn thì 100ms cũng là quá cao. Thế nên đôi khi nó ko phải vấn đề với anh nhưng nó sẽ là vấn đề với người khác.

Tôi ko đủ giỏi để lead team 500 dev, chỉ may mắn là 1 dev trong team đó. Cái tôi muốn nói là ORM ko phải là thứ anh cần để làm những cái việc anh nói, chỉ cần 1 cái query builder tốt là xong, ngay cả team 500 người cũng đang làm tốt mọi thứ mà ko cần ORM. Tôi nhấn mạnh là Query Builder nhé, tôi ko đề cập tới bất kì chữ Rawquery nào, bản thân tôi cũng ko bao giờ muốn viết rawquery cả.
 
chốt lại e thấy bác 4nh7i3m nói khá đúng cho các trường hợp normal, vậy xin mạn phép hỏi bác (và các bác khác nữa) mấy case mà các bác trên này có hỏi:
  • xử lý ntn với gọi các service với nhau - có nên gọi không?
  • với các lệnh Join thì đặt ở repository nào của table nào?
 
chốt lại e thấy bác 4nh7i3m nói khá đúng cho các trường hợp normal, vậy xin mạn phép hỏi bác (và các bác khác nữa) mấy case mà các bác trên này có hỏi:
  • xử lý ntn với gọi các service với nhau - có nên gọi không?
  • với các lệnh Join thì đặt ở repository nào của table nào?
Cái điều này mình cũng khúc mắc bao lâu nay, mong các bác chỉ dạy :big_smile:
 
phần 1: có người test rồi.

phần 2: ORM nó có nhiều tác dụng hơn vậy nhiều. Tất nhiên nó cũng có trade off, đó là performance. Cái anh đang nói thì chỉ cần query builder là đủ, tôi là dev trong 1 repo có 500 dev, vẫn đang dùng query builder thay vì ORM vì vấn đề performance.

phần 3: GetUserByID, không thể select theo từng field vì khi đó rất khó maintain, nhưng cũng ko thể select * nếu table quá lớn. Giải pháp tôi từng làm cho team đơn giản là tách theo từng cụm. Ví dụ GetAll -> UserEntity, GetCredential -> UserCredentialEntity, GetContact -> UserContactEntity, GetProfile -> UserProfileEntity. Nếu cần 2 loại entity sẽ GetAll. Tất nhiên nó ko tối ưu, nhưng nó sẽ cân bằng cho cả performance và maintainance.
GetUserById select theo từng field cho từng trường hợp nếu dùng EF Core + Automapper Projection vẫn làm dc nhé, lúc đó chỉ cần đưa vào từng IMapper instance có profile khác nhau là select field khác nhau liền. Tất nhiên output của hàm GetUserById phải định nghĩa đủ props cho tất cả các trường hợp, nhưng câu query mà EF Core generate ra thì tuỳ vô IMapper instance
 
GetUserById select theo từng field cho từng trường hợp nếu dùng EF Core + Automapper Projection vẫn làm dc nhé, lúc đó chỉ cần đưa vào từng IMapper instance có profile khác nhau là select field khác nhau liền. Tất nhiên output của hàm GetUserById phải định nghĩa đủ props cho tất cả các trường hợp, nhưng câu query mà EF Core generate ra thì tuỳ vô IMapper instance
xin link tham khảo được ko ạ
 
chốt lại e thấy bác 4nh7i3m nói khá đúng cho các trường hợp normal, vậy xin mạn phép hỏi bác (và các bác khác nữa) mấy case mà các bác trên này có hỏi:
  • xử lý ntn với gọi các service với nhau - có nên gọi không?
  • với các lệnh Join thì đặt ở repository nào của table nào?

Cái điều này mình cũng khúc mắc bao lâu nay, mong các bác chỉ dạy :big_smile:

Về vụ circular reference:
"Cách tốt nhất để giải quyết một vấn đề phát sinh là đừng để phát sinh cái vấn đề đó".
Nói chung là tách 2 service ra thành 3 cái, hoặc gộp 2 service thành 1 cái nếu có quá nhiều phần chung. Làm sao làm để ko có circular reference. Còn nếu bắt buộc thì dùng property injection thay cho constructor injection, nhưng tôi prefer cách ko nên để có circular reference. Ai chửi tui ngu ko giải quyết được đi né tránh vấn đề thì tui chịu. :shame:

Về vụ Join các Repository:
Cái này theo tôi nói ở post trước là dùng thẳng ORM framework trong implementation của Data Access Service (DAS) để tận dụng hết features của ORM framework.
https://voz.vn/t/van-de-ve-separate-repository-service-controller.183643/post-5706814

Còn vẫn muốn dùng Repository map 1-1 với table thì phải abstract và wrap các method của ORM như Join, Query, Order, Create, Insert, Update, Delete, Transaction operations... nói chung là đi wrap gần như tất cả các method của ORM. Thường người ta sẽ làm nó trong 1 base class là GenericRepository<T> như thế này rồi gọi method Join giữa 2 Repo như link dưới:
https://entityframework.net/knowled...generic-repository-pattern---entity-framework
C#:
using (MyDbContext ctx = new MyDbContext())
{
  var studentRep = new Repository<Student>(ctx);
  var standardRep = new Repository<Standard>(ctx);
  var studentToStandard = studentRep.GetAll().Join(standardRep.GetAll(),
                        student => student.StandardRefId,
                        standard => standard.StandardId,
                        (stud, stand) => new { Student=stud, Standard=stand }).ToList();
}

Nhưng tôi ko prefer cách phía trên lắm vì thật sự ko cần thiết, trừ trường hợp thay đổi ORM thôi. Cái vụ Repository pattern này thường hay bị lạm dụng vì hàng loạt ví dụ về nó, thậm chí trên web của Microsoft cũng có 1 bài về Unit of Work và Repository pattern như bài này:
https://docs.microsoft.com/en-us/as...f-work-patterns-in-an-asp-net-mvc-application

Cái design này có 1 bất cập là tác giả sử dụng unitOfWork chỉ như một thằng manager quản lý các Repo và wrap các method của ORM lại, như vậy thì vô tình xem persistence layer xài ORM rồi. Điển hình là đây, các code này trong Controller, sử dụng unitOfWork rồi gọi cả Save, Dispose...
C#:
// ...
unitOfWork.CourseRepository.Insert(course);
unitOfWork.Save();
//...
unitOfWork.CourseRepository.Delete(id);
unitOfWork.Save();
// ...
unitOfWork.Dispose();
Làm như cách trên thì dự án này fix luôn là tầng persistence layer là xài ORM rồi. Nếu như persistence layer là gọi 3rd API của cloud storage thì 2 hàm unitOfWork.Save(); unitOfWork.Dispose(); lại bị dư thừa, lúc đó phải implement lại và để trống? Theo tôi thì nó nên là Data Access Service và độc lập với persistence layer bên dưới, trong implementation của courseDAS.Insert() và courseDAS.Delete(id) thì xài trực tiếp ORM hoặc gọi 3rd API hay gì thì tuỳ vào persistence layer của mình.
C#:
// ...
courseDAS.Insert(course);
//...
courseDAS.Delete(id);

Bonus thêm cái link bàn về Repository và ORM ở đây:
https://www.thereformedprogrammer.net/is-the-repository-pattern-useful-with-entity-framework-core/
 
GetUserById select theo từng field cho từng trường hợp nếu dùng EF Core + Automapper Projection vẫn làm dc nhé, lúc đó chỉ cần đưa vào từng IMapper instance có profile khác nhau là select field khác nhau liền. Tất nhiên output của hàm GetUserById phải định nghĩa đủ props cho tất cả các trường hợp, nhưng câu query mà EF Core generate ra thì tuỳ vô IMapper instance

ko dùng EF nhưng đoán là object user chứa nhiều properties, thím chỉ fetch những cái nào cần, số còn lại null hết?
làm như vậy thì khó maintain, vì khi sử dụng object user đó phải biết những field nào đc fetch những field nào không.
 
lội được vài trang, thấy đuối quá, ko đủ sức lội hết :))
Comment với chủ thớt là em +1 cho ý của chủ thớt nhé.
Nhờ chủ thớt nói lý do mà tại sao các lead lại ko cho chạy service layer lên, để xem có uẩn khúc gì không.
Cá nhân em thì cứ cái gì chia được là sẽ chia :)) tự cân đo đong đếm chán, chứ cũng không theo khuôn khổ nào. Cơ mà MVC thì vẫn cái khung chính là MVC 3 tầng thôi. Em thấy thằng Jhipster nó generate code cũng oke, nhìn theo nó làm practice cũng ổn
 
ko dùng EF nhưng đoán là object user chứa nhiều properties, thím chỉ fetch những cái nào cần, số còn lại null hết?
làm như vậy thì khó maintain, vì khi sử dụng object user đó phải biết những field nào đc fetch những field nào không.
chuẩn như thím nói. trade-off thôi nhưng vẫn có cách để workaround bằng cách tạo 1 object projection có các properties chính là EF Entities, sau đó khai báo mapper sẽ map tu properties qua output object, thủ công hơn xí nhưng mà lợi ích nhiều hơn, cách này mình hay dùng cho câu query join nhiều tables, và output properties lấy từ nhiều tables
 

Thống kê chủ đề

Ngày tạo
soledad86,
Người trả lời cuối
freedom.9,
Trả lời
217
Lượt xem
33.247
Quay lại
Lên đầu trang