Search code examples
hibernatealiascriteriarestrictions

Hibernate alias to a simple boolean field


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

Solution

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