Hibernate alias to a simple boolean field

Boris Horvat picture Boris Horvat · Dec 26, 2012 · Viewed 16.6k times · Source

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));

Answer

Raul Rene picture Raul Rene · Dec 27, 2012

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:

  1. 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;
    } 
    
  2. Make sure your DB field is a BIT (or the corresponding data type for boolean values on the DB you are using).

  3. 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"));