I am struggling with the Hibernate Criteria API.
In class Conversation
I have:
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "Conversation_ConversationParticipants",
joinColumns = @JoinColumn(name = "ConversationID"),
inverseJoinColumns = @JoinColumn(name = "ConversationParticipantID"))
private List<ConversationParticipant> participants;
And in class ConversationParticipant
I have:
@OneToOne
@JoinColumn(name = "ParticipantID")
private User participant;
@Type(type = "true_false")
@Column(name = "Viewed")
private boolean viewed;
In my criteria I have
Criteria criteria = super.createCriteria();
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.createAlias("participants", "participants");
criteria.createAlias("participants.participant", "participant");
criteria.add(Restrictions.eq("participant.id", user.getId()));
return (List<Conversation>) criteria.list();
This all works ok and I can see all of the conversations for the given user. However, what I want is to see all of the conversations that the user has not viewed yet. To do so, I try to add:
criteria.add(Restrictions.eq("participants.viewed", false));
However, this returns 0 conversations (if I put 'true' I get the same result and I have checked db and made sure that there are values with both true and false). How can I achieve this? What am I doing wrong?
The query that is run is:
from
Conversations this_
inner join
Conversation_ConversationParticipants participan4_
on this_.id=participan4_.ConversationID
inner join
ConversationParticipants participan1_
on participan4_.ConversationParticipantID=participan1_.id
inner join
Users participan2_
on participan1_.ParticipantID=participan2_.id
where
participan1_.Viewed=?
and participan2_.id=?
DB Table:
CREATE TABLE ConversationParticipants(ID BIGINT NOT NULL IDENTITY, Viewed CHAR(1), Type VARCHAR (255), ParticipantID BIGINT, PRIMARY KEY (ID));
Based on the answer below, I was able to make it work by using:
criteria.add(Restrictions.eq("participants.viewed", Boolean.FALSE));
What you are trying to do is theoretically correct and should work. Nevertheless, I am thinking of some possible things that may prove to be wrong:
Make sure your getter and setter are properly used. Your code should look like:
private boolean viewed;
@Type(type = "true_false")
@Column(name = "Viewed")
public boolean isViewed() {
return viewed;
}
public void setViewed(boolean viewed) {
this.viewed = viewed;
}
Make sure your DB field is a BIT
(or the corresponding data type for boolean values on the DB you are using).
If neither 1 nor 2 work, I suggest removing the @Type
annotation as it is not necessary, although it should do no harm.
Edit:
You are trying to map a boolean
to a char
. I do not really understand why you would use a char(1)
instead of a BIT
. Nevertheless, if you want to do so, work with a String
in the model class.
Then, if your DB column holds 0 or 1, use:
criteria.add(Restrictions.eq("participants.viewed", "0"));
Or if your DB column holds true/false, use:
criteria.add(Restrictions.eq("participants.viewed", "false"));