2012-04-22 30 views
7

Tôi có một kịch bản khá chuẩn, theo đó tôi có một bảng Người dùng có user_id là PK và một bảng Vai trò có role_id là PK. Hai bảng có liên quan thông qua mối quan hệ nhiều đến nhiều (ví dụ: Người dùng có thể có nhiều vai trò và vai trò có thể được áp dụng cho nhiều người dùng) và sau đó tôi có một bảng nối kết được gọi là users_has_roles. Chỉ có hai cột trong users_has_roles là users_user_id và roles_role_id.JPA tồn tại nhiều đến nhiều

Tôi đã tạo ra các lớp thực thể (xem bên dưới) và tôi không có vấn đề gì khi lưu trữ dữ liệu vào bảng người dùng và vai trò, nhưng tôi đã thất bại một cách thảm hại bất cứ điều gì với bảng users_has_roles. . Trước khi tôi phát điên có thể ai đó đưa tôi ra khỏi đau khổ của tôi và chỉ cho tôi cách tôi nên đi về việc thêm một users_user_id với một roles_role_id tương ứng vào bảng users_has_roles để người dùng của tôi có thể có vai trò?

My Users.java tổ chức lớp:

@Entity 
@Table(name = "users") 
@XmlRootElement 
@NamedQueries({ 
@NamedQuery(name = "Users.findAll", query = "SELECT u FROM Users u"), 
@NamedQuery(name = "Users.findByUserId", query = "SELECT u FROM Users u WHERE u.userId = :userId"), 
@NamedQuery(name = "Users.findByUsername", query = "SELECT u FROM Users u WHERE u.username = :username"), 
@NamedQuery(name = "Users.findByPassword", query = "SELECT u FROM Users u WHERE u.password = :password")}) 
public class Users implements Serializable { 
private static final long serialVersionUID = 1L; 
@Id 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 60) 
@Column(name = "user_id") 
private String userId; 
@Basic(optional = false) 
@NotNull 
@Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email") 
@Size(min = 1, max = 45) 
@Column(name = "username") 
private String username; 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 120) 
@Column(name = "password") 
private String password; 
@JoinTable(name = "users_has_roles", joinColumns = { 
    @JoinColumn(name = "users_user_id", referencedColumnName = "user_id")}, inverseJoinColumns = { 
    @JoinColumn(name = "roles_role_id", referencedColumnName = "role_id")}) 
@ManyToMany 
private Collection<Roles> rolesCollection; 
@OneToMany(cascade = CascadeType.ALL, mappedBy = "usersUserId") 
private Collection<UserAccount> userAccountCollection; 
@OneToMany(cascade = CascadeType.ALL, mappedBy = "usersUserId") 
private Collection<UserDetails> userDetailsCollection; 

... 

All the getter and setter methods etc. 

My Roles.java tổ chức lớp:

@Entity 
@Table(name = "roles") 
@XmlRootElement 
@NamedQueries({ 
@NamedQuery(name = "Roles.findAll", query = "SELECT r FROM Roles r"), 
@NamedQuery(name = "Roles.findByRoleId", query = "SELECT r FROM Roles r WHERE r.roleId = :roleId"), 
@NamedQuery(name = "Roles.findByRoleName", query = "SELECT r FROM Roles r WHERE r.roleName = :roleName"), 
@NamedQuery(name = "Roles.findByRolePermission", query = "SELECT r FROM Roles r WHERE r.rolePermission = :rolePermission"), 
@NamedQuery(name = "Roles.findByRoleDescription", query = "SELECT r FROM Roles r WHERE r.roleDescription = :roleDescription")}) 
public class Roles implements Serializable { 
private static final long serialVersionUID = 1L; 
@Id 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 60) 
@Column(name = "role_id") 
private String roleId; 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 45) 
@Column(name = "role_name") 
private String roleName; 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 45) 
@Column(name = "role_permission") 
private String rolePermission; 
@Size(max = 45) 
@Column(name = "role_description") 
private String roleDescription; 
@ManyToMany(mappedBy = "rolesCollection") 
private Collection<Users> usersCollection; 

... 

All the getter and setter methods etc. 

Cảm ơn

---- CẬP NHẬT ----

// New Users 
Users currentUser = new Users(); 
currentUser.setUserId(userId); 
currentUser.setUsername(email); 
currentUser.setPassword(password); 
getUsersFacade().create(currentUser); 

Trả lời

6

Ví dụ của bạn hoạt động tốt (EclipseLink 2.3, MySQL). Có khả năng sự cố là một phần của mã mà bạn không hiển thị. Ví dụ trong việc thêm phần tử vào rolesCollection. Lỗi điển hình là ví dụ để thêm phần tử chỉ vào bên không sở hữu.

Để duy trì nó, bạn phải quan tâm đến quan hệ sở hữu bên (không có ánh xạ), để giữ biểu đồ đối tượng trong bộ nhớ phù hợp với cơ sở dữ liệu, bạn nên luôn sửa đổi cả hai mặt của quan hệ.

Tôi đã thử nó với sau:

// method to add element to rolesCollection 
    public void addRoles(Roles r) { 
     rolesCollection.add(r); 
    } 

    //first created new instances of Users and Roles 
    // then: 
    tx.begin(); 
    users.addRoles(r); 
    //it is not needed for persisting, but here you can also 
    //add user to roles. 
    em.persist(users); 
    em.persist(r); 
    tx.commit(); 
+1

Hi Mikko, tôi vẫn còn bối rối! Tôi không hiểu mã hoạt động như thế nào.Nếu tôi cần phải sửa đổi cả hai mặt của quan hệ, tôi có cần phải thêm các phần tử vào cả vai tròCollection và usersCollection không? Có vẻ như bạn chỉ đang thêm vào vai tròCollection. Ngoài ra tôi đang bối rối những gì tôi đang thêm vào Bộ sưu tập tương ứng. RoleCollection có yêu cầu cả user_user_id và roles_role_id không? – tarka

+0

Vấn đề là: để thực hiện được duy trì cho cơ sở dữ liệu, yêu cầu tối thiểu là sửa đổi bên sở hữu (một không có mappedBy). Điểm xấu là sau đó bộ sưu tập với mappedBy không đồng bộ. Đó là lý do tại sao nó nói chung là tốt hơn để sửa đổi cả hai bên, có nghĩa là thêm các yếu tố cho cả hai vai tròCollection và rolesCollection. –

+0

Ok cách tốt nhất là thêm các phần tử vào cả Bộ sưu tập ... nhưng tôi phải thêm gì vào mỗi Bộ sưu tập? thế nào để tôi thêm cả một user_id và một role_id cho cả hai? – tarka

8

Ok trước hết nhờ vào Mikko cho dẫn tôi đến câu trả lời. Tôi chỉ muốn đăng câu trả lời có thể trực tiếp hữu ích cho bất kỳ ai khác có thể ở vị trí tôi đang ở. Ngoài ra, điều này dựa trên thời điểm Eureka để nó có thể không đúng về mặt kỹ thuật nhưng đây là cách tôi nhìn thấy nó.

Vấn đề lớn mà tôi phải đối mặt là trong MySQL, tôi có thể thấy bảng chuyển tiếp dưới dạng bảng riêng lẻ! (xin lỗi tôi không thể đăng một hình ảnh của sơ đồ EER của tôi nhưng tôi dường như không có đủ đặc quyền tại thời điểm này) Vì vậy, tôi giả định rằng Java cũng sẽ thấy bảng cầu nối như một bảng! Vâng nó không. Bảng chuyển tiếp đó không thực sự tồn tại trong Java như một bảng thông thường, nó được thể hiện bằng loại bộ sưu tập bảng đối lập mà bạn liên kết với nó.

Cách dễ nhất để xem nó cho tôi là hoàn toàn quên bảng cầu nối và tập trung vào hai bảng 'thực' và kết hợp dữ liệu trong các bảng đó. Đoạn mã sau KHÔNG PHẢI là thực hành tốt nhất vì tôi chỉ đơn giản là đặt role_id nhưng nó chỉ tốt để chỉ ra quan điểm của tôi.

List<Roles> userRoleList = new ArrayList<Roles>(); 

Users currentUser = new Users(); 
currentUser.setUserId(userId); 
currentUser.setUsername(email); 
currentUser.setPassword(password); 

Roles userRole = new Roles(); 
userRole.setRoleId("2"); 

userRoleList.add(userRole); 
currentUser.setRolesCollection(userRoleList); 

getUsersFacade().create(currentUser); 

Hy vọng rằng sẽ giúp bất kỳ ai khác đang đấu tranh với nhiều mối quan hệ.

(NB. Tôi đã chỉnh sửa mã câu hỏi ban đầu để sử dụng một danh sách thay vì một Bộ sưu tập để dễ nhưng bạn có thể chỉ cần cũng sử dụng bất kỳ loại nào khác phù hợp với nhu cầu của bạn.)

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