2012-01-07 39 views
8

Tôi đang sử dụng khung công tác Java + Spring cho ứng dụng web. Tôi không sử dụng bất kỳ công cụ ORM nào. Thay vào đó, tôi đang cố gắng mô hình hóa các quan hệ db như các đối tượng Java bằng cách sử dụng mẫu DAO/DTO đơn giản. Bất cứ khi nào DTO chính xác tương ứng với một bảng duy nhất trong cơ sở dữ liệu, nó rất thẳng về phía trước. Nhưng nếu có các bảng tham chiếu đến các bảng khác bằng cách sử dụng các khóa ngoại, tôi không chắc chắn cách tiếp cận tốt nhất cho điều này là gì. Nhìn vào Stackoverflow cho câu trả lời tương tự nhưng không thể tìm thấy một trong những nhu cầu của tôi. Tôi muốn đưa ra một ví dụ rất cụ thể - Giả sử có hai thực thể Người dùng và Nhóm. Tôi có một DTO người dùng và DTO nhóm, mỗi người có UserDao (JdbcUserDao) và GroupDao (JdbcGroupDao) tương ứng.Thiết kế DTO có mối quan hệ khóa ngoài

Bây giờ tôi có mối quan hệ trong DB kết nối Người dùng và Nhóm. Một người dùng có thể thuộc về nhiều nhóm. Tên bảng là User_Group_Association có định nghĩa DB sau:

user_id | group_id

Tại đây user_id là khóa ngoài tham chiếu đến bảng người dùng. Tương tự group_id đề cập đến bảng nhóm. Khi tôi mô hình DTO này trong Java, tôi nên làm một cái gì đó như thế này:

public class UserGroupAssoc { 
    private int userId; 
    private int groupId; 

    //Setters and getters follow 
} 

HOẶC nó phải như thế này:

public class UserGroupAssoc { 
    private User user; 
    private Group group; 

    //Setters and getters follow 
} 

Đặc biệt trường hợp sử dụng giao diện người dùng: Tôi muốn hiển thị tên người dùng và các nhóm tương ứng tên họ thuộc về. Một cái gì đó như this-

Tên -> Nhóm Tên

Keshav -> Quản trị, enduser, ReportAdmin
Kiran -> ReportAdmin
Pranav -> enduser

Trong cách tiếp cận đầu tiên để thiết kế DTO, tôi sẽ cần lấy lại chi tiết người dùng (tên) và chi tiết nhóm (tên) một lần nữa từ DB. Trong phương pháp thứ hai, tôi sẽ cần tìm nạp các đối tượng User và Group khi tôi xây dựng chính đối tượng UserGroupAssoc.

Trong lẽ là một cách tiếp cận thứ ba tôi có thể thiết kế các UserGroupAssoc DTO như sau:

public class UserGroupAssoc { 
    private String userName; 
    private String groupName; 
    private int userId; 
    private int groupId; 

    //Setters and getters follow 
} 

Trong phương pháp thứ ba này, tôi tham gia bảng trong SQL để có được chỉ các lĩnh vực cần thiết cho việc sử dụng hợp cụ thể và sau đó mô hình DTO cho phù hợp.

Cách tiếp cận chuẩn để đạt được kịch bản này là gì? Đang tham gia bảng ngay trong thiết kế DTO? Một số có ý kiến ​​rằng một DTO nên tương ứng với chỉ có MỘT bảng và các đối tượng liên quan nên được tổng hợp trong lớp ứng dụng. Điều đó có chi phí làm nhiều việc tìm nạp đối tượng từ DB phải không? Quá nhầm lẫn về cách tiếp cận đúng, xin lỗi vì lời giải thích dài như vậy!

Trả lời

6

Disclaimer: Tôi không phải là một chuyên gia ORM ...

... nhưng trong một cổ điển many-to-many relations bạn không cần phải mô hình dữ liệu thứ ba (UserGroupAssoc).Lớp User sẽ chứa một tập hợp các Group s:

public class User { 
    // ... user fields ... 
    List<Group> groups; 
    // ... getters/setters ... 
} 

Nếu bạn cũng cần mối quan hệ nghịch đảo (một nhóm chứa người dùng) lớp Group sẽ trông như thế này:

public class Group { 
    // ... group fields ... 
    List<User> users; 
    // ... getters/setters ... 
} 

Và một lần nữa, cách cổ điển để thực hiện việc này là sử dụng "đối tượng tên miền" (DTO của bạn) trong bộ sưu tập (UserGroup thay vì userIdgroupId).

Bạn thường cần một đối tượng miền thứ ba chỉ khi bảng hiệp hội (User_Group_Association) chứa một cái gì đó khác hơn user_idgroup_id (có thể một số mã uỷ quyền cho phép người dùng phải được thêm vào nhóm, bất cứ điều gì):

user_id | group_id | auth_code 

Trong trường hợp này lớp UserGroupAssoc có thể có cấu trúc này:

public class UserGroupAssoc { 
    private User user; 
    private Group group; 
    private String authorizationCode; 

    // ... setters/getters ... 
} 

và mối quan hệ nhiều-nhiều giữa UserGroup sẽ chuyển đổi thành hai mối quan hệ nhiều-với-một với đối tượng miền mới này. Thông thường, các đối tượng miền được ưu tiên sử dụng (UserGroup thay vì userIdgroupId).

Cách tiếp cận chuẩn để đạt được kịch bản này là gì?

Vâng, nếu bạn đang sử dụng khung ORM, đó sẽ là cách tiêu chuẩn mà khung làm việc. Nhưng vì bạn có giải pháp ORM tùy chỉnh, thật khó để nói.

Bạn có đang tham gia các bảng trong thiết kế DTO không?

Tại sao thiết kế DTO trong lớp ứng dụng bị ảnh hưởng bằng cách nối các bảng trong cơ sở dữ liệu? Đây là trường hợp của object-relational impedance mismatch và cũng có thể là law of leaky abstraction vì bạn không thể trừu tượng hoàn toàn tên miền quan hệ thành miền đối tượng giữ thư 1: 1.

Một số ý kiến ​​cho rằng một DTO chỉ tương ứng với MỘT bảng và các đối tượng liên quan sẽ được tổng hợp trong lớp ứng dụng. Điều đó có chi phí làm nhiều việc tìm nạp đối tượng từ DB phải không?

ORM có một số hạn chế (xem lại không phù hợp với trở ngại đối tượng đối với một số vấn đề bạn có thể gặp phải) và rất khó mô hình đối tượng miền của bạn để phù hợp với cơ sở dữ liệu quan hệ hoặc ngược lại. Báo cáo là ví dụ tốt theo hướng này.

Báo cáo thường tổng hợp dữ liệu từ nhiều bảng. Điều này tất nhiên không có vấn đề gì đối với một số phép nối SQL, nhưng làm thế nào bạn sẽ lập bản đồ kết quả cho các DTO? Khi bạn tự mình nói ...

Bất cứ khi nào DTO chính xác tương ứng với một bảng duy nhất trong cơ sở dữ liệu, nó là rất thẳng về phía trước

... nhưng kết quả báo cáo sẽ không lập bản đồ vào một bảng duy nhất, nó sẽ phải ánh xạ tới các mảnh từ nhiều bảng hơn.

Tùy thuộc vào nhu cầu của bạn trong ứng dụng, bạn có thể kết thúc với một số lớp tìm kiếm lạ hoặc với các câu lệnh SQL khó xử. Bạn có thể sẽ chạy nhiều truy vấn hơn cần thiết để có được các mô hình đối tượng thích hợp và các liên kết giữa chúng; hoặc bạn có thể có nhiều DTO tương tự hơn để giới hạn số lượng chuyến đi đến cơ sở dữ liệu và đạt được hiệu suất tốt hơn.

Vì vậy, những gì tôi đang cố gắng nói (một lần nữa tuyên bố từ chối trách nhiệm rằng tôi không phải là chuyên gia ORM) là không phải tất cả các ứng dụng đều là một ứng cử viên tốt cho ORM; nhưng nếu bạn xem xét đi trước với nó có thể nhìn vào cách Hibernate/JPA là địa chỉ các vấn đề hoặc thậm chí đi trước và sử dụng chúng để thay thế.

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