Có phải thực tế xấu mà bộ điều khiển gọi kho lưu trữ thay vì dịch vụ?


43

Có phải thực tế xấu mà bộ điều khiển gọi kho lưu trữ thay vì dịch vụ?

để giải thích thêm:

Tôi nhận ra rằng trong bộ điều khiển thiết kế tốt gọi dịch vụ và kho lưu trữ sử dụng dịch vụ.

nhưng đôi khi trong bộ điều khiển tôi không có / cần bất kỳ logic nào và chỉ cần tìm nạp từ db và chuyển nó để xem.

và tôi có thể làm điều đó bằng cách chỉ gọi kho lưu trữ - không cần gọi dịch vụ - đó có phải là thông lệ xấu không?


Làm thế nào bạn gọi dịch vụ? Thông qua giao diện REST?
Robert Harvey

2
Tôi sử dụng phương pháp thiết kế đó bản thân mình khá phổ biến. Trình điều khiển của tôi (hoặc một lớp nhà soạn nhạc cơ bản) sẽ yêu cầu dữ liệu từ hoặc gửi dữ liệu đến repo và sau đó chuyển nó đến bất kỳ lớp dịch vụ nào cần xử lý. Không có lý do để kết hợp các lớp xử lý dữ liệu với các lớp quản lý / truy xuất dữ liệu, chúng là những mối quan tâm khác nhau mặc dù tôi biết cách tiếp cận điển hình là làm theo cách đó.
Jimmy Hoffa

3
Meh. Nếu đó là một ứng dụng nhỏ và bạn chỉ đang cố lấy dữ liệu từ cơ sở dữ liệu, thì lớp dịch vụ sẽ lãng phí thời gian trừ khi lớp dịch vụ đó là một phần của một số API công khai, chẳng hạn như giao diện REST. "Sữa tốt cho bạn hay xấu cho bạn?" Phụ thuộc vào việc bạn không dung nạp đường sữa.
Robert Harvey

4
Không có quy tắc cứng và nhanh nào mà bạn nên có Bộ điều khiển -> Dịch vụ -> Cấu trúc kho lưu trữ trên Bộ điều khiển -> Kho lưu trữ. Chọn đúng mẫu cho ứng dụng phù hợp. Những gì tôi muốn nói là bạn nên làm cho ứng dụng của bạn nhất quán.
NikolaiDante

Có lẽ bạn có thể đưa ra một dịch vụ chung chỉ chuyển tiếp yêu cầu của bạn đến kho lưu trữ và sau đó trả về. Điều này có thể hữu ích để giữ một giao diện thống nhất và sẽ đơn giản nếu trong tương lai bạn cần thêm một dịch vụ thực tế để làm một cái gì đó trước khi gọi kho lưu trữ.
Henrique Barcelos

Câu trả lời:


32

Không, hãy nghĩ về nó theo cách này: một kho lưu trữ là một dịch vụ (cũng).

Nếu các thực thể bạn truy xuất thông qua kho lưu trữ xử lý hầu hết logic nghiệp vụ thì không cần các dịch vụ khác. Chỉ cần có kho lưu trữ là đủ.

Ngay cả khi bạn có một số dịch vụ mà bạn phải thông qua để thao túng các thực thể của mình. Lấy thực thể từ kho lưu trữ trước và sau đó chuyển nó đến dịch vụ đã nói. Có thể tung HTTP 404 trước khi thử thậm chí rất thuận tiện.

Ngoài ra, để đọc kịch bản phổ biến, bạn chỉ cần thực thể chiếu nó lên DTO / ViewModel. Có một lớp dịch vụ ở giữa sau đó thường dẫn đến rất nhiều phương thức chuyển qua khá xấu.


2
Nói hay lắm! Sở thích của tôi là gọi các kho lưu trữ, và chỉ trong trường hợp, sau đó một kho lưu trữ là không đủ (tức là hai thực thể phải được sửa đổi bằng cách sử dụng các kho lưu trữ khác nhau), tôi tạo một dịch vụ chịu trách nhiệm về hoạt động này và gọi nó từ bộ điều khiển.
Zygimantas

Tôi đã nhận thấy một mã khá phức tạp chỉ để biện minh cho việc sử dụng dịch vụ. Vô lý, ít nhất ...
Gi1ber7

Vì vậy, kho lưu trữ của tôi trả về một danh sách 'đối tượng kinh doanh' mà tôi cần chuyển đổi thành 'đối tượng xml', lý do đó có đủ để có một lớp dịch vụ không? Tôi đang gọi một phương thức trên mỗi đối tượng để chuyển đổi nó sang loại khác và thêm vào một danh sách mới.
bot_bot

Truy cập DAO trực tiếp rất nguy hiểm trong các bộ điều khiển, nó có thể khiến bạn dễ bị tiêm SQL và cho phép truy cập vào các hành động nguy hiểm như ,, xóa ALL '' Tôi chắc chắn sẽ tránh được.
Anirudh

4

Nó không phải là thực hành xấu cho một bộ điều khiển để gọi một kho lưu trữ trực tiếp. Một "dịch vụ" chỉ là một công cụ khác, vì vậy hãy sử dụng nó ở nơi có ý nghĩa.

NikolaiDante bình luận:

... Chọn đúng mẫu cho ứng dụng phù hợp. Những gì tôi muốn nói là bạn nên làm cho ứng dụng của bạn nhất quán.

Tôi không nghĩ tính nhất quán là khía cạnh quan trọng nhất. Một lớp "dịch vụ" có nghĩa là gói gọn một số logic mức cao hơn để bộ điều khiển không cần phải thực hiện nó. Nếu không có "logic mức cao hơn" cần thiết cho một hoạt động nhất định, chỉ cần truy cập trực tiếp vào kho lưu trữ.

Để quảng bá tốt tách biệt các mối quan tâm và khả năng kiểm tra, kho lưu trữ phải là một phụ thuộc mà bạn đưa vào dịch vụ thông qua một hàm tạo:

IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);

service.DoSomething(...);

Nếu tìm kiếm các bản ghi trong cơ sở dữ liệu cần một số loại truy vấn được tham số hóa, một lớp dịch vụ có thể là một nơi tốt để lấy mô hình xem của bạn và xây dựng một truy vấn được kho lưu trữ thực hiện.

Tương tự, nếu bạn có một mô hình khung nhìn phức tạp cho một biểu mẫu, một lớp dịch vụ có thể gói gọn logic của việc tạo, cập nhật và xóa các bản ghi bằng cách gọi các phương thức trên Mô hình / Thực thể Miền của bạn, sau đó duy trì chúng bằng cách sử dụng kho lưu trữ.

Đi theo hướng ngược lại, nếu bộ điều khiển của bạn cần lấy bản ghi bằng Id của nó, thì việc ủy ​​thác cho một đối tượng dịch vụ cho việc này giống như đánh một cái đinh bấm bằng búa tạ - đó là cách bạn cần nhiều hơn.

Tôi đã thấy rằng bộ điều khiển ở vị trí tốt nhất để xử lý giao dịch hoặc đối tượng Đơn vị công việc . Sau đó, bộ điều khiển hoặc đối tượng Đơn vị công việc sẽ ủy quyền cho các đối tượng dịch vụ cho các hoạt động phức tạp hoặc trực tiếp đến kho lưu trữ cho các hoạt động đơn giản (như tìm bản ghi theo Id).

public class ShoppingCartsController : Controller
{
    [HttpPost]
    public ActionResult Edit(int id, ShoppingCartForm model)
    {
        // Controller initiates a database session and transaction
        using (IStoreContext store = new StoreContext())
        {
            // Controller goes directly to a repository to find a record by Id
            ShoppingCart cart = store.ShoppingCarts.Find(id);

            // Controller creates the service, and passes the repository and/or
            // the current transaction
            ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);

            if (cart == null)
                return HttpNotFound();

            if (ModelState.IsValid)
            {
                // Controller delegates to a service object to manipulate the
                // Domain Model (ShoppingCart)
                service.UpdateShoppingCart(model, cart);

                // Controller decides to commit changes
                store.SaveChanges();

                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }
    }
}

Tôi nghĩ rằng sự kết hợp của các dịch vụ và làm việc với các kho lưu trữ trực tiếp là hoàn toàn chấp nhận được. Bạn có thể đóng gói thêm giao dịch trong một đối tượng Đơn vị công việc nếu bạn cảm thấy cần thiết.

Phân tích trách nhiệm diễn ra như sau:

  • Bộ điều khiển kiểm soát dòng chảy của ứng dụng
    • Trả về "404 Không tìm thấy" nếu giỏ hàng không có trong cơ sở dữ liệu
    • Hiển thị lại biểu mẫu với thông báo xác thực nếu xác thực không thành công
    • Lưu giỏ hàng nếu mọi thứ kiểm tra
  • Bộ điều khiển ủy quyền cho một lớp dịch vụ để thực thi logic nghiệp vụ trên Mô hình miền (hoặc Thực thể) của bạn. Đối tượng dịch vụ không nên thực hiện logic kinh doanh! Họ thực hiện logic kinh doanh.
  • Bộ điều khiển có thể ủy quyền trực tiếp vào kho cho các hoạt động đơn giản
  • Các đối tượng dịch vụ lấy dữ liệu trong mô hình khung nhìn và ủy quyền cho Mô hình miền để thực thi logic nghiệp vụ (ví dụ: đối tượng dịch vụ gọi các phương thức trên Mô hình miền trước khi gọi các phương thức trên kho lưu trữ)
  • Các đối tượng dịch vụ ủy quyền cho các kho lưu trữ dữ liệu
  • Bộ điều khiển nên:
    1. Quản lý thời gian tồn tại của giao dịch hoặc
    2. Tạo một đối tượng Đơn vị công việc để quản lý thời gian giao dịch

1
-1 để đưa DbContext vào bộ điều khiển thay vì repo. Repo có nghĩa là để quản lý các nhà cung cấp dữ liệu để trong trường hợp không có ai khác phải thay đổi nhà cung cấp dữ liệu (từ MySQL sang các tệp JSON phẳng, thay đổi ở một nơi)
Jimmy Hoffa

@JimmyHoffa: Tôi thực sự đang nhìn lại mã tôi đã viết và thành thật mà nói, tôi tạo một đối tượng "bối cảnh" cho kho lưu trữ của mình, không cần thiết cơ sở dữ liệu. Tôi nghĩ DbContextlà một tên xấu trong trường hợp này. Tôi sẽ thay đổi điều đó. Tôi sử dụng NHibernate và các kho lưu trữ (hoặc bối cảnh nếu tiện dụng) quản lý phần cuối cơ sở dữ liệu, vì vậy việc thay đổi cơ chế lưu giữ không yêu cầu thay đổi mã bên ngoài ngữ cảnh.
Greg Burghardt

bạn dường như đang nhầm lẫn bộ điều khiển với kho lưu trữ bởi vẻ ngoài của mã của bạn ... Ý tôi là, "bối cảnh" của bạn hoàn toàn sai và hoàn toàn không tồn tại trong bộ điều khiển.
Jimmy Hoffa

6
Tôi không phải trả lời và tôi không chắc đây là một câu hỏi hay, nhưng tôi không bình chọn vì tôi nghĩ cách tiếp cận của bạn là thiết kế tồi. Không có cảm giác khó khăn, tôi chỉ ngăn cản bối cảnh được sở hữu bởi các bộ điều khiển. IMO một bộ điều khiển không nên bắt đầu và thực hiện các giao dịch như thế này. Đó là công việc của bất kỳ số nơi nào khác, tôi thích các bộ điều khiển ủy thác mọi thứ không chỉ đơn giản là đáp ứng yêu cầu HTTP đến một nơi khác.
Jimmy Hoffa

1
Một kho lưu trữ, thường chịu trách nhiệm cho tất cả các thông tin ngữ cảnh dữ liệu để đảm bảo rằng không có gì khác cần biết bất cứ điều gì về mối quan tâm dữ liệu ngoài những gì chính tên miền cần biết
Jimmy Hoffa

1

Nó phụ thuộc vào kiến ​​trúc của bạn. Tôi sử dụng Spring và giao dịch luôn được quản lý bởi các dịch vụ.

Nếu bạn gọi các kho lưu trữ trực tiếp cho các hoạt động ghi (Hoặc các dịch vụ đơn giản không có logic chỉ đơn giản là ủy thác cho kho lưu trữ), có lẽ bạn đang sử dụng một số giao dịch cơ sở dữ liệu cho một hoạt động phải được thực hiện trong một. Điều đó sẽ dẫn đến dữ liệu không mạch lạc trong cơ sở dữ liệu của bạn. Theo nguyên tắc chung, các hoạt động cơ sở dữ liệu sẽ hoạt động hoặc không thành công, nhưng các hoạt động nửa hoạt động là nguyên nhân gây đau đầu.

Vì lý do đó, tôi nghĩ rằng việc gọi các kho lưu trữ trực tiếp từ các bộ điều khiển, hoặc sử dụng các dịch vụ ủy nhiệm đơn giản, là một thực tế tồi. Bạn bắt đầu làm nó chỉ để đọc, và rất sớm bạn, hoặc một hoặc bạn bè của bạn sẽ bắt đầu làm nó cho các hoạt động viết.

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.