简体   繁体   中英

sql generated with hql query with composite user type

I'm using hibernate 3.6.1 and i have a strange behaviour on the sql generated by hql.

Here is the hql:

from Floor as floor where (floor.type != :var1)

type is a composite user type (see bottom) and is composed by two values a long and an int and a Type is different from another Type if at least one of the two values is different. I want to extract all the floors with type different from a specified one, so all the floor with floor.oid<>oi1 OR floor.number1<>num1 where oi1 and number1 is from a specified Type. But the generated sql has an AND instead a OR:

select
    floor0_.id as id0_,
    floor0_.number as number0_,
    floor0_.oid as oid0_,
    floor0_.number1 as number4_0_ 
from
    Floor floor0_ 
where
    floor0_.oid<>? 
    and floor0_.number1<>?

i expect that the condition should be

floor0_.oid<>? 
or floor0_.number1<>?

Floor implementation:

public class Floor {
    private Long id;
    private Integer number;
    private Type type;


    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    public Long getId() {
        return id;
    }

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



    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }
}

Type implementation:

public class Type implements CompositeUserType {
    private Long oid;
    public Long getOid() {
        return oid;
    }
    public void setOid(Long oid) {
        this.oid = oid;
    }
    private Integer number1;


    public Integer getNumber1() {
        return number1;
    }
    public void setNumber1(Integer number1) {
        this.number1 = number1;
    }


    @Override
    public String[] getPropertyNames() {
        String[] names = {"oid", "number1"};
        return names;
    }
    @Override
    public org.hibernate.type.Type[] getPropertyTypes() {
        BasicTypeRegistry registry = new BasicTypeRegistry();
        org.hibernate.type.Type longType = registry.getRegisteredType(LongType.INSTANCE.getRegistrationKeys()[0]);
        org.hibernate.type.Type intType = registry.getRegisteredType(IntegerType.INSTANCE.getRegistrationKeys()[0]);
        org.hibernate.type.Type[] types = { longType, intType };
        return types;
    }
    @Override
    public Object getPropertyValue(Object component, int property)
            throws HibernateException {
        if (component == null) return null;
        if (! (component instanceof Type)) {
            throw new HibernateException("wrong component type");
        }
        Type type = (Type) component;
        switch(property) {
        case 0:
            return type.oid;
        case 1: 
            return type.number1;
        default:
            throw new HibernateException("wrong component type");
        }
    }
    @Override
    public void setPropertyValue(Object component, int property, Object value)
            throws HibernateException {
        // boh!!!
        if (component == null) {
            throw new HibernateException("set property invoked on a null instance");
        }
        if (! (component instanceof Type)) {
            throw new HibernateException("set property invoked on a wrong component type");
        }
        Type type = (Type) component;
        String valueString = value.toString();
        switch(property) {
        case 0:
            type.oid  = Long.parseLong(valueString);
        case 1: 
            type.number1 = Integer.parseInt(valueString);
        default:
            throw new HibernateException("set property invoked on a wrong component type");
        }

    }
    @Override
    public Class returnedClass() {
        // TODO Auto-generated method stub
        return Type.class;
    }
    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if(x == y) return true;
        if (x == null && y != null) return false;
        if (x != null && y == null) return false;
        if(! (x instanceof Type) || ! (y instanceof Type)) {
            return false;   
        }
        Type xt = (Type)x;
        Type yt = (Type)y;
        return (xt.oid == yt.oid && xt.number1 == yt.number1);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        if (x == null) {
            return 0;
        } else {
            if (x instanceof Type) {
                Type xt = (Type) x;
                return xt.number1.hashCode() * 17 + xt.oid.hashCode();
            } else {
                throw new HibernateException("hashCode invoked on a non Type instance");
            }
        }
    }
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names,
            SessionImplementor session, Object owner)
            throws HibernateException, SQLException {

        Type t = null;
        if (!rs.wasNull()){
            t = new Type();

            Long id = rs.getLong(names[0]);
            Integer number = rs.getInt(names[1]);

            t.oid = id;
            t.number1 = number;
        }
        return t;
    }
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index,
            SessionImplementor session) throws HibernateException, SQLException {
        Type t = (Type) value;

        st.setLong(0, t.oid);
        st.setInt(1, t.number1);

    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        if (value == null)
            return null;

        Type oldType = (Type) value;

        Type t = new Type();
        t.setOid(oldType.getOid());
        t.setNumber1(oldType.getNumber1());

        return t;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value, SessionImplementor session)
            throws HibernateException {
        return value.toString();
    }

    @Override
    public Object assemble(Serializable cached, SessionImplementor session,
            Object owner) throws HibernateException {
        return cached;
    }
    @Override
    public Object replace(Object original, Object target,
            SessionImplementor session, Object owner) throws HibernateException {

        return original;
    }

}

is there something i'm wrong ?

Thanks for any help

It's certainly a bug in Hibernate, feel free to report it .

As a workaround you can use Critera for this query, it doesn't have this bug.

Also note that CompositeUserType is usually used to persist another class, not the same one, therefore your implementation of Type can be confusing, see 6.4.3. Custom types using org.hibernate.usertype.CompositeUserType .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM