Làm thế nào để ngăn chặn các phương thức truy cập dữ liệu trùng lặp lấy dữ liệu tương tự?


8

Trong hầu hết mọi dự án tôi làm việc với một nhóm, cùng một vấn đề dường như xuất hiện. Ai đó viết mã UI cần dữ liệu và viết phương thức truy cập dữ liệu:

AssetDto GetAssetById(int assetId)

Một tuần sau, một người khác đang làm việc trên một phần khác của ứng dụng và cũng cần một AssetDtonhưng bây giờ bao gồm cả 'người phê duyệt' và viết như sau:

AssetDto GetAssetWithApproversById(int assetId)

Một tháng sau, ai đó cần một tài sản nhưng bây giờ bao gồm 'câu hỏi' (hoặc 'chủ sở hữu' hoặc 'yêu cầu đang chạy', v.v.):

AssetDto GetAssetWithQuestionsById(int assetId)
AssetDto GetAssetWithOwnersById(int assetId)
AssetDto GetAssetWithRunningRequestsById(int assetId)

Và nó thậm chí còn tồi tệ hơn khi các phương pháp như GetAssetWithOwnerAndQuestionsByIdbắt đầu xuất hiện.

Bạn thấy mô hình nổi lên: một đối tượng được gắn vào biểu đồ đối tượng lớn và bạn cần các phần khác nhau của biểu đồ này ở các vị trí khác nhau.

Tất nhiên, tôi muốn ngăn chặn việc có một số lượng lớn các phương thức gần như giống nhau. Nó chỉ đơn giản là một vấn đề kỷ luật nhóm hoặc có một số mô hình tôi có thể sử dụng để ngăn chặn điều này? Trong một số trường hợp, có thể có các phương pháp riêng biệt, nghĩa là có được một tài sản với các yêu cầu đang chạy có thể tốn kém vì vậy tôi không muốn bao gồm các phương thức này mọi lúc. Làm thế nào để xử lý các trường hợp như vậy?


1
Bạn có thể sử dụng một cái gì đó như grails xử lý tải lười biếng (gorm thông qua ngủ đông) các thuộc tính - khi cố gắng truy cập. Bằng cách này, bạn chỉ cần gọi a = getAssetById(x)và sau đó có thể gọi a.questions, v.v. mà không cần tải chúng một cách cụ thể vì hệ thống ORM cơ bản sẽ tải nó cho bạn khi cố gắng truy cập.
techfoobar

1
Điều đó sẽ có thể nhưng yêu cầu bạn giữ một số bối cảnh cơ sở dữ liệu mở trong khi truy vấn. Tôi thà không có loại kiến ​​thức này bị rò rỉ ra khỏi lớp truy cập dữ liệu. Và bạn có ít quyền kiểm soát hơn đối với các truy vấn được thực hiện. Nhưng một lựa chọn rất thú vị ...
Ronald Wildenberg

Vâng và đó là toàn bộ vấn đề tách nó ra trong DTO tôi đoán. Grails dành cho cách làm việc không phải DTO ..
techfoobar

Chạy các truy vấn kết thúc mở từ một giao diện sẽ yêu cầu giao diện đó phải là ngôn ngữ truy vấn cụ thể của miền. Câu trả lời được chấp nhận tương tự như vậy.
mike30

Câu trả lời:


4

Cú pháp khôn ngoan, tôi sẽ tạo một đối tượng xây dựng truy vấn trung gian với giao diện trôi chảy:

// all the basic, cheap to query fields
AssetDto a = AssetRetriever(asset_id).fetch() 

// some common expensive fields
AssetDto a = AssetRetriever(asset_id).withOwner().withQuestion().fetch() 

// numerous less common fields may not command dedicated methods
AssetDto a = AssetRetriever(asset_id).withFields("foo", "bar").fetch() 

// Better yet, use an enum and enjoy static checking
AssetDto a = AssetRetriever(asset_id).withFields(F_OWNER, F_QUESTION).fetch() 

Tôi hy vọng nó đủ rõ ràng để thực hiện. Phương pháp duy nhất sẽ thực sự chạm vào cơ sở dữ liệu là fetch().


Tôi thực sự thích giải pháp này. Nó thực thi những gì tôi muốn đạt được với một cú pháp dễ hiểu và rõ ràng và nó cung cấp rất nhiều khả năng để mở rộng giao diện và tối ưu hóa các truy vấn SQL.
Ronald Wildenberg

2

Khi làm việc với đối tượng lớn, điều này thực sự phổ biến. Trong khi thêm các phương thức mới làm tăng hiệu suất, nó làm giảm đáng kể khả năng bảo trì. Và một lần nữa bạn cần phải chọn giữa hai.

Tôi đề nghị bạn nên có một phương thức trả về (không nhất thiết là dữ liệu nhỏ nhất) thường được sử dụng, một phương thức khác trả về toàn bộ đối tượng và có thể thêm một vài cho các tài nguyên đắt nhất.

Một cách tiếp cận khác là có các phương thức chỉ trả về các trường cần thiết của đối tượng, như AssetQuestions GetAssetQuestionsById(int assetId)hoặc Owners GetAssetOwnersById(int assetId).

Cùng với điều này, bạn cần thiết lập một số quy tắc liên quan đến việc truy xuất dữ liệu. Ví dụ, nếu ai đó cần 5 trường của đối tượng và có một phương thức hiện có trả về 8, thì nên sử dụng phương thức hiện có.


Tôi hy vọng sẽ có một số mô hình tôi có thể thực thi để vấn đề không xảy ra nhưng tôi sợ giải pháp của bạn là tốt nhất. Nó đi xuống kỷ luật và nghiên cứu nhiều hơn khi bạn viết mã truy cập dữ liệu mới.
Ronald Wildenberg

Tôi thích giải pháp của bạn giới thiệu các phương pháp bổ sung để truy xuất các đối tượng liên quan. Nó có thể tốn một ít hiệu suất vì bạn không còn THAM GIA dữ liệu trong cơ sở dữ liệu nhưng để duy trì thì có lẽ đó là một cải tiến lớn.
Ronald Wildenberg

3
Có một giải pháp "điên rồ" xuất hiện trong đầu tôi: tạo một loại với trường boolean cho từng tham số, đặt đúng cho các trường bạn muốn truy xuất và truyền đối tượng đó làm tham số)))
superM

Điều đó cũng đã qua tâm trí của tôi và nhược điểm duy nhất là bạn phải chuẩn bị sẵn sàng để đưa tất cả các kết hợp có thể vào tài khoản trong mã truy cập dữ liệu của bạn. Mặc dù tất nhiên bạn có thể viết các truy vấn rất hiệu quả cho các trường hợp phổ biến nhất ...
Ronald Wildenberg

Tôi đoán điều đó cũng khó duy trì, nhưng có thể hoạt động trong một số trường hợp
superM

1

Gần đây tôi đã trải qua vấn đề tương tự và áp dụng giải pháp sau:

Các phương thức truy cập dữ liệu chỉ nên lấy dữ liệu từ một tài nguyên duy nhất (ví dụ: bảng cơ sở dữ liệu) và nếu quy trình cần các đối tượng liên quan được gắn vào đối tượng chính thì nó sẽ gọi phương thức chịu trách nhiệm cho các đối tượng tương ứng đó.

Theo cách này, nếu bạn cần một tài sản với những người phê duyệt, bạn nên tạo một phương thức mặt tiền để tham gia vào các đối tượng.

Thí dụ:

public Class AssetFacade {

   public AssetDto getAssetWithQuestionsByAssetId(int assetId) { 

      AssetDto asset = AssetDao.getAssetById(assetId);
      List<QuestionDto> questions = AssetDao.getQuestionsByAssetId(assetId);
      asset.setQuestions(questions);

      return asset;
   };
 }

1
Đây là một giải pháp khả thi nhưng tôi không muốn bạn mất tất cả các khả năng tối ưu hóa truy cập dữ liệu thông qua cơ sở dữ liệu. Tức là một truy vấn có tham gia trên ba bảng có thể nhanh hơn ba truy vấn riêng biệt.
Ronald Wildenberg

Đồng ý với bạn, nhưng không thể tìm ra giải pháp tốt hơn tại thời điểm đó. Vui mừng bạn đã tạo ra câu hỏi này cho tôi để tìm hiểu một cách tốt hơn quá!
marcioggs

0

Nó chỉ đơn giản là một vấn đề kỷ luật nhóm hoặc có một số mô hình tôi có thể sử dụng để ngăn chặn điều này?

Vâng, đó là vấn đề của một số hướng dẫn trong cách đặt tên cho nhóm. Bạn có thể đặt 4 phương thức đơn giản như GetEntityById (), Get ALLEntities (), SetEntity (), DeleteEntityById ().

Ngoài ra, bạn có thể có hai dto với cách đặt tên AssetSimpleDto GetAssetById(assetId)và một dto chi tiết khác được gọi là AssetDto GetAssetDetailById(assetId). Phương pháp đầu tiên và dto được tùy chỉnh để mang lại mức tối thiểu, trong khi thứ hai là mang tất cả thông tin liên quan mà chức năng của bạn có thể cần.


Thật không may, trường hợp này không dễ như 'đơn giản' hay 'nhận tất cả' nên điều này không thực sự giải quyết được vấn đề tiềm ẩn. Điều này có thể sẽ khiến mọi người sử dụng phương thức 'get all' vì họ cần một phần của biểu đồ đối tượng không được trả về bởi 'get Simple'.
Ronald Wildenberg
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.