-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Restrictions.in() won't work with multiple composite keys
PostPosted: Thu Sep 09, 2010 4:09 am 
Newbie

Joined: Thu Sep 09, 2010 3:30 am
Posts: 2
I'm using Hibernate with a Restrictions.in() criteria on a table with a composite id. Everything works fine when I put just one id in the query but when I put multiple id:s it doesn't work.

The query generated by Hibernate looks like this:

Code:
select this_.part_id as part1_2_0_, this_.player_id as player2_2_0_, this_.timestamp as timestamp2_0_ from user_achievements.part_player this_ where (1=1) and (this_.part_id, this_.player_id) in ((?, ?), (?, ?))


When I ran it manually in a query browser it worked just fine so I turned tracing on in log4j and it turned out that hibernate binds the parameters wrong when you pass in multiple keys.

I pass in a collection of my composite-id class called PlayerPartPk:

Code:
.....

public List<PlayerPart> findAllByPlayerAndPart(List<PlayerPartPk> partPks) {
        Criteria criteria = getCriteriaForSearchCriteria(new PlayerPart()).add(Restrictions.in("id", partPks));
        return criteria.list();

    }


.....

protected final Criteria getCriteriaForSearchCriteria(final T searchCriteria) {
        Example example = Example.create(searchCriteria);
        Criteria criteria = getSession().createCriteria(persistentClass);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        return criteria.add(example);
    }



Code:
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.hibernate.annotations.Proxy;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;

import javax.persistence.*;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.Serializable;

@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@Entity
@Proxy(lazy = false)
@Table(name = "part_player", schema = "user_achievements")
public class PlayerPart implements Serializable {
   
    private static final String PERSISTENT_DATE_TIME = "org.joda.time.contrib.hibernate.PersistentDateTime";

    private PlayerPartPk id;
    private DateTime timestamp;

    @EmbeddedId
    public PlayerPartPk getId() {
        return id;
    }

    public void setId(PlayerPartPk playerPartPk) {
        this.id = playerPartPk;
    }

    @Column(name ="timestamp", nullable = true)
    @XmlJavaTypeAdapter(DateTimeXmlAdapter.class)
    @JsonSerialize(using = DateTimeJsonSerializer.class)
    @JsonDeserialize(using = DateTimeJsonDeserializer.class)
    @Type(type = PERSISTENT_DATE_TIME)
    public DateTime getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(DateTime timestamp) {
        this.timestamp = timestamp;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        PlayerPart that = (PlayerPart) o;

        if (this.getId() != null ? !this.getId().equals(that.getId()) : that.getId() != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return this.getId() != null ? this.getId().hashCode() : 0;
    }
}


Code:
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;

@Embeddable
public class PlayerPartPk implements Serializable {
    private Integer partId;
    private Integer playerId;

    @Column(name ="part_id", nullable = false)
    public Integer getPartId() {
        return partId;
    }

    public void setPartId(Integer partId) {
        this.partId = partId;
    }

    @Column(name ="player_id", nullable = false)
    public Integer getPlayerId() {
        return playerId;
    }

    public void setPlayerId(Integer playerId) {
        this.playerId = playerId;
    }

    @Override
    public boolean equals(Object other) {
        boolean result = true;

        if(!(other instanceof PlayerPartPk)) {
            return false;
        }

        Integer otherPartId = ((PlayerPartPk)other).getPartId();
        Integer otherPlayerId = ((PlayerPartPk)other).getPlayerId();

        if(this.getPartId() == null || otherPartId == null) {
            result = false;
        } else {
            result = this.getPartId().equals(otherPartId);
        }

        if(this.getPlayerId() == null || otherPlayerId == null) {
            result = false;
        } else {
            result = this.getPlayerId().equals(otherPlayerId);
        }

        return result;
    }

    @Override
    public int hashCode() {
        int code = 0;

        if(this.getPartId() != null) {
            code += this.getPartId();
        }

        if(this.getPlayerId() != null) {
            code += this.getPlayerId();
        }

        return code;
    }
}


But instead of binding the parameters of the query this way:

Code:
select this_.part_id as part1_2_0_, this_.player_id as player2_2_0_, this_.timestamp as timestamp2_0_ from user_achievements.part_player this_ where (1=1) and (this_.part_id, this_.player_id) in ((partId1, playerId1), (partId2, playerId2))




it binds it this way:

Code:
select this_.part_id as part1_2_0_, this_.player_id as player2_2_0_, this_.timestamp as timestamp2_0_ from user_achievements.part_player this_ where (1=1) and (this_.part_id, this_.player_id) in ((partId1, partId2), (playerId1, playerId2))



The output from the jboss log looks like this:

Code:
16:48:24,882 INFO  [STDOUT] Hibernate: select this_.part_id as part1_2_0_, this_.player_id as player2_2_0_, this_.timestamp as timestamp2_0_ from user_achievements.part_player this_ where (1=1) and (this_.part_id, this_.player_id) in ((?, ?), (?, ?))
16:48:24,882 TRACE [AbstractBatcher] preparing statement
16:48:24,884 TRACE [IntegerType] binding '5' to parameter: 1
16:48:24,884 TRACE [IntegerType] binding '11' to parameter: 2
16:48:24,884 TRACE [IntegerType] binding '123' to parameter: 3
16:48:24,884 TRACE [IntegerType] binding '123' to parameter: 4


but should be this:

Code:
16:48:24,882 INFO  [STDOUT] Hibernate: select this_.part_id as part1_2_0_, this_.player_id as player2_2_0_, this_.timestamp as timestamp2_0_ from user_achievements.part_player this_ where (1=1) and (this_.part_id, this_.player_id) in ((?, ?), (?, ?))
16:48:24,882 TRACE [AbstractBatcher] preparing statement
16:48:24,884 TRACE [IntegerType] binding '5' to parameter: 1
16:48:24,884 TRACE [IntegerType] binding '123' to parameter: 2
16:48:24,884 TRACE [IntegerType] binding '11' to parameter: 3
16:48:24,884 TRACE [IntegerType] binding '123' to parameter: 4


Is this a bug in Hibernate or am I doing something really wrong?

Thanks in advance.

Jonas


Top
 Profile  
 
 Post subject: Re: Restrictions.in() won't work with multiple composite keys
PostPosted: Fri Sep 10, 2010 5:20 am 
Newbie

Joined: Wed Feb 10, 2010 5:07 am
Posts: 11
Bump. I'm experiencing this problem too in 3.2.4.


Top
 Profile  
 
 Post subject: Re: Restrictions.in() won't work with multiple composite keys
PostPosted: Tue Sep 14, 2010 2:52 am 
Newbie

Joined: Thu Sep 09, 2010 3:30 am
Posts: 2
I'm using version 3.2.6


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.