rbobin
rbobin

Reputation: 39

org.hibernate.PropertyAccessException: with many to many relation

I've encountered a problem while establishing new table (UserMessage) for many to many relation (User and Message tables). When I try to access a row from the mapping table I get an exception: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.package.model.User.userid

UserMessage entity is necessary for further addition of properties to the relation table.

Data is accessed via:

    Session session = (Session) entityManager.getDelegate();
    String hql = "FROM Message M, UserMessage UM WHERE M.messageid = UM.pk.message and UM.pk.user = :id";
    Query query = session.createQuery(hql);
    query.setParameter("id", id);
    query.list();

My classes:

User.java

@Entity
@Table(name = "USER")
public class User {
    @Id @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    @Column(nullable = false)
    private Long userid;

    @Column(unique = true, nullable = false)
    private String username;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.user", cascade = {CascadeType.PERSIST})
    private Set<UserMessage> inbox = new HashSet<UserMessage>();

    public User() {
    }

    public Long getUserid() {
        return userid;
    }

    public void setUserid(Long id) {
        this.userid = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Set<UserMessage> getInbox() {
        return inbox;
    }

    public void setInbox(Set<UserMessage> inbox) {
        this.inbox = inbox;
    }

    public void addMessageToUser(Message message){
        UserMessage userMessage = new UserMessage();
        userMessage.setUser(this);
        userMessage.setMessage(message);
        inbox.add(userMessage);
    }
}

Message.java

@Entity
@Table(name = "MESSAGE")
public class Message {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long messageid;
    private String subject;
    private String body;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.message",cascade = {CascadeType.PERSIST})
    private Set<UserMessage> toUser = new HashSet<UserMessage>();

    public Set<UserMessage> getToUser() {
        return toUser;
    }

    public void setToUser(Set<UserMessage> toUser) {
        this.toUser = toUser;
    }

    public void addUserToMessage(User user){
        UserMessage userMessage = new UserMessage();
        userMessage.setUser(user);
        userMessage.setMessage(this);
        toUser.add(userMessage);
    }

    public Message() {
    }

    public Long getMessageid() {
        return messageid;
    }

    public void setMessageid(Long id) {
        this.messageid = id;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

UserMessage.java

@Entity
@Table(name = "USER_MESSAGE")
@AssociationOverrides({
        @AssociationOverride(name = "pk.user", joinColumns = @JoinColumn(name = "userid")),
        @AssociationOverride(name = "pk.message", joinColumns = @JoinColumn(name = "messageid"))
})
public class UserMessage{

    @EmbeddedId
    private UserMessagePK pk = new UserMessagePK();


    public UserMessagePK getPk(){
        return pk;
    }

    public void setPk(UserMessagePK pk){
        this.pk = pk;
    }

    public UserMessage(){
    }

    @Transient
    public User getUser(){
        return this.pk.getUser();
    }

    @Transient
    public Message getMessage(){
        return this.pk.getMessage();
    }

    public void setUser(User user){
        this.pk.setUser(user);
    }

    public void setMessage(Message message){
        this.pk.setMessage(message);
    }
}

UserMessagePK.java

@Embeddable
public class UserMessagePK implements Serializable {

    private static final long serialVersionUID = 1L;

    @ManyToOne
    private User user;

    @ManyToOne(cascade = CascadeType.REFRESH)
    private Message message;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }


    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    public UserMessagePK(User user, Message message){
        this.user = user;
        this.message = message;
    }

    public UserMessagePK(){
    }
}

What is wrong?

Upvotes: 0

Views: 696

Answers (2)

rbobin
rbobin

Reputation: 39

The problem was in query.

select distinct M from Message M join M.toUser t where t.pk.user = :user works perfectly.

Upvotes: 1

forhas
forhas

Reputation: 11991

I would suggest a different approach. In the User class, instead of holding a set of UserMessage, write this:

@Entity
@Table(name = "Users")
public class User implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "User_Id")
private Long userid;

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "USER_MESSAGE", joinColumns = @JoinColumn(name = "User_Id"), inverseJoinColumns = @JoinColumn(name = "Message_Id"))
protected Set<Message> userMessages = new HashSet<>(0);

public void addUserMessage(Message toAdd) {
if (null != toAdd) {
    this.userProviders.add(toAdd);
}
}

public void getUserMessages() {
return this.userMessages;
}

public void setUserMessages(Set<Message> userMessages) {
this.userMessages.clear();
this.userMessages.addAll(userMessages);
}

// add getter and setter to id

...

In the Message class you should have:

@Entity
@Table(name = "User_Messages")
public class Message implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Message_Id")
protected long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name = "Users_Messages", joinColumns = @JoinColumn(name = "Message_Id", insertable = false, updatable = false), inverseJoinColumns = @JoinColumn(name = "User_Id"))
protected User user;

// add getters and setters
...

You can get rid of UserMessagePK class and UserMessage as well (why would you need those?). Now when you generate your tables (you could use hbm2ddl tool) you should have a join table for the relationship of User<-->Message.

Now you can run your queries.

Upvotes: 0

Related Questions