2013-03-19 64 views
14

Tôi đang sử dụng Spring JDBC và tôi không chắc chắn về cách làm việc với nhiều quan hệ một-nhiều (hoặc nhiều-nhiều). Trong trường hợp này tôi đang tiêm một kho lưu trữ vào một trong các resultsetextractors của tôi để tôi có thể truy xuất các kết hợp của nó. Đây có phải là cách để làm điều đó không? Nó có tồi không? Có cách nào khác tốt hơn không?Nhiều mối quan hệ một-nhiều trong Spring JDBC

Lưu ý: Tôi đã bỏ qua việc tiêm kho

public class SomeResultSetExtractor implements ResultSetExtractor { 

    public Object extractData(ResultSet rs) throws SQLException, DataAccessException { 
    List result = new LinkedList(); 

    while (rs.next()) { 
     SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2)); 
     result.add(object); 

     List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId); 
     object.setOtherObjects(otherObjects); 
     // and so on 
    } 

    return result; 

    } 
} 

Okey nên sau khi đọc Dmytro Polivenok câu trả lời tôi đã thay đổi giao diện RowMapper thay vào đó và tôi hiện đang sử dụng các kho khác để cư tất cả các hiệp hội như Tôi thể hiện trong ví dụ của tôi. Đây có phải là cách hay để làm điều đó không?

+0

Kho lưu trữ có bắt đầu một truy vấn SQL mới không? – tkr

Trả lời

4

Tôi nghĩ thực tiễn tốt cho các truy vấn SQL JDBC và SQL nói chung là sử dụng một truy vấn cho mỗi thực thể.

Ví dụ: giả định mô hình này:

  • khách hàng (ID khách hàng, tên, tuổi, ...)
  • Địa chỉ (ID khách hàng, chủng loại, đường phố, thành phố, ...)
  • PaymentOption (ID khách hàng, cardnumber, cardtype , ...)

  • khách hàng 1 --- * Địa chỉ

  • khách hàng 1 --- * PaymentOption

tôi sẽ xây dựng 3 truy vấn, 3 DAO, 3 ResultSetExtractors/RowcallbackHandlers:

  • CustomerDao với readCustomerData (Khách hàng hoặc danh sách)
  • AddressDao với readAddressForCustomer (Khách hàng hoặc danh sách)
  • PaymentOptionDao với readPaymentOptionsForCustomer (Khách hàng hoặc Danh sách)

Nếu bạn sẽ nướng điều này trong truy vấn 1, bạn sẽ phải xây dựng một số logic để hoàn nguyên sản phẩm cartas.

  • I.e. nếu khách hàng có 3 địa chỉ và 2 tùy chọn thanh toán, truy vấn sẽ trả về 6 hàng.
  • Điều này khá khó khăn, nếu Địa chỉ hoặc PaymentOption không có khóa chính.

Đối với nhiều nhiều:

  • khách hàng * --recommends-- * Sản phẩm

tôi có lẽ sẽ xây dựng:

  • CustomerDao.readRecommendationsAndProductKeys
  • getDistinctListOfProductKeysFromRecommendations
  • ProductDao.readProducts
  • replaceProductKeysByProductsOnRecommendations

Như vậy, bạn có thể tái sử dụng ProductDao.readProducts cho

  • khách hàng * --buys-- * Sản phẩm hoặc
  • ProductGroup 1 --- * Sản phẩm
+0

Cảm ơn, điều này cũng tương tự như tôi đã làm. – LuckyLuke

+0

Điều này không hiệu quả khi bạn thực hiện một số chuyến đi khứ hồi tới cơ sở dữ liệu? Nếu bạn cần tất cả dữ liệu, truy vấn của bạn trả về 100 đối tượng, bạn sẽ lần lượt phát hành thêm 300 truy vấn để có được dữ liệu hoàn chỉnh, cho tổng số cho 301 truy vấn – greyfox

+0

ý tưởng là cho mỗi đợt truy vấn. Bạn có thể gọi readCustomerData với 100 Id khách hàng và chia kết quả dựa trên Id khách hàng. Vì vậy, đối với 100 khách hàng, bạn sẽ vẫn chỉ cần 3 truy vấn. – tkr

4

Tôi nghĩ rằng mã của bạn sẽ hoạt động, nhưng mối quan tâm ở đây là về việc sử dụng ResultSetExtractor chủ yếu cho khung JDBC, và đối với hầu hết các trường hợp, documentation khuyến nghị sử dụng RowMapper.

Cách tiếp cận thay thế sẽ là có phương pháp trong DAO của bạn để chọn và ánh xạ đối tượng mẹ. Sau đó, đối với mỗi đối tượng gọi phương thức lưu trữ hoặc riêng khác để chọn và ánh xạ đối tượng con, sau đó liên kết các đối tượng con với cha mẹ dựa trên loại mối quan hệ của bạn (một chiều hoặc hai chiều). Cách tiếp cận này cũng có thể cho phép bạn kiểm soát xem bạn có muốn tải các đối tượng con hay không.

Ví dụ, bạn có thể kiểm tra ứng dụng Spring PetClinic trong đó có SimpleJdbcClinic class

Nếu bạn có thể sử dụng các khuôn khổ khác, bạn có thể xem xét mybatis, nó là nhiều về lập bản đồ và cho phép bạn kiểm soát mã SQL của bạn.

+0

Xin chào, tôi không chắc chắn nếu tôi hiểu câu trả lời của bạn đúng cách. Giả sử bạn có các lớp: Phim, Diễn viên, Thể loại và Nhận xét. Bạn muốn trả về một đối tượng phim với tất cả các liên kết của nó: Một bộ phim có nhiều diễn viên, nhiều bình luận và một thể loại. Bạn làm điều đó như thế nào? – LuckyLuke

+0

Bạn có thể có phương thức getMovies, sẽ thực hiện lựa chọn cho phim và thể loại, và ánh xạ chúng vào các đối tượng. Sau đó, đối với mỗi movie, hãy gọi Repository cho các tác nhân có select/map và Repository cho các chú thích với select/map (hoặc nếu các diễn viên và chú thích tồn tại trong ngữ cảnh của bạn chỉ về phim thì bạn có thể làm điều này trong các phương thức riêng). Sau khi thiết lập ý kiến ​​và tác giả đối tượng phim –

+0

Okey, vì vậy nếu tôi thay đổi giao diện rowmapper thì tốt hơn. Tuy nhiên, bạn làm gì với nhiều trường hợp? Cách tốt nhất để ánh xạ chúng là gì? Giả sử mỗi bộ phim có nhiều diễn viên và mỗi diễn viên thuộc về nhiều bộ phim. Sau đó, bạn có một bảng tham gia? Bạn có tạo một phương thức trong ví dụ kho lưu trữ tác nhân được đặt tên findAllActorsForMovie sử dụng bảng nối kết và bảng diễn viên để tạo kết quả không? Cũng giống như bạn làm trong một-nhiều? – LuckyLuke

Các vấn đề liên quan