-->
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.  [ 4 posts ] 
Author Message
 Post subject: Problems with bi-directional indexed Collections
PostPosted: Wed Oct 11, 2006 9:33 am 
Senior
Senior

Joined: Tue Jul 25, 2006 9:05 am
Posts: 163
Location: Stuttgart/Karlsruhe, Germany
Hibernate version:3.2CR1 (Ships with JBoss 4.0.4GA)

Mapping documents: none annotations being used

Name and version of the database you are using: PostgreSQL 8.1.4

The generated SQL (show_sql=true):
Code:
select expression2_.id as id941_0_, restrictio4_.id as id941_1_, expression5_.id as id942_2_,
   expression2_.type as type941_0_, expression2_.description as descript4_941_0_, expression2_.expr as expr941_0_,
   expression2_.DISCRIMINATOR as DISCRIMI1_941_0_, restrictio4_.type as type941_1_,
   restrictio4_.description as descript4_941_1_, restrictio4_.expr as expr941_1_,
   restrictio3_.expression_hierarchy_id as expression1_0__, restrictio3_.restrictions_id as restrict2_0__,
   restrictio3_.rule_index as rule3_0__, expression5_.expression_id as expression3_942_2_,
   expression5_.role as role942_2_, expression5_.targetEntity_id as
targetEn4_942_2_,
   expression5_.expression_id as expression3_1__, expression5_.id as id1__,
   expression5_.expression_index as expression5_1__
from TargetEntity targetenti0_
   inner join ExpressionTarget expression1_ on targetenti0_.id=expression1_.targetEntity_id
   inner join expression_hierarchy expression2_ on expression1_.expression_id=expression2_.id
   inner join expression_hierarchy_expression_hierarchy restrictio3_ on expression2_.id=restrictio3_.expression_hierarchy_id
   inner join expression_hierarchy restrictio4_ on restrictio3_.restrictions_id=restrictio4_.id
   left outer join ExpressionTarget expression5_ on restrictio4_.id=expression5_.expression_id
where targetenti0_.id=?

IS GENERATED FROM
Query tmpQuery = mEntityManager.createQuery("SELECT e.expression FROM TargetEntity " +
                "t INNER JOIN t.expressionTargets e JOIN FETCH e.expression.restrictions r " +
                "LEFT OUTER JOIN FETCH r.expressionTargets g LEFT OUTER JOIN FETCH g.targetEntity " +
                "WHERE t.id = :pk").setParameter("pk", 1);


The above query works until i try and join a table to itself (ExpressionTarget), and i know this brings back the incorrect result (double the ammount required, this WILL be changed to 2 seperate queries). But i want to be able to use OneToMany bidirectional Indexed Collections (using @IndexColumn) but it is not working. I have 1 UniDirectional Indexed Collection and that works fine as the column index is populated, but in bi-directional mode the idexes are always null !! The exception i got when running the query was

Code:
org.hibernate.HibernateException: null index column for collection: XXX.Expression.expressionTargets


I have read around and found some suggestions not to use the mappedBy in the @OneToMany but i find this confusing as in the examples on the JBoss webisite http://docs.jboss.org/ejb3/app-server/tutorial/entity/entity.html says that this is how to do it.

Also is it possible to have 2 bidirectional indexed collection (OneToMany) on the same table ? When i did drop the mappedBy only one index was populated. Another point to note is that the Expression table is a single inheritance table.

Any help/advice will be greatly appreciated.

Thanks,

Andy


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 11, 2006 11:22 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
check the hibernate reference documentation about bidirectional indexed collection, there are some constraints you need to follow, because such a concept is not really natural

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 12, 2006 10:50 am 
Senior
Senior

Joined: Tue Jul 25, 2006 9:05 am
Posts: 163
Location: Stuttgart/Karlsruhe, Germany
I managed to get it to poulate the index colums, by removing mapped by in the @OneToMany side. Removing this mean that it creates 2 extra tables (1 per relation)

The problem i am now having is getting Hibernate to query the data, as hibernate is forgetting to include one of the tables created by removing mappedBy.

the current set up of the entities is

ExpressionHierarchy entity
Code:
@Entity
@Table(name = "expressionhierarchy")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR",
                     discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("expression")
public class Expression implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = -1091620752774725110L;
    private int mId;
    private ExpressionType mType;
    private String mExpr;
    private String mDescription;   
    private List<ExpressionTarget> mExpressionTargets = new ArrayList<ExpressionTarget>();
   
    public enum ExpressionType {
        REGEX, EQUATION, SET
    }
   
    @Id
    public int getId() {
        return mId;
    }
   
    public void setId(final int pId) {
        mId = pId;
    }
   
    public String getExpr() {
        return mExpr;
    }
   
    public void setExpr(final String pExpr) {
        mExpr = pExpr;
    }
   
    public ExpressionType getType() {
        return mType;
    }
   
    public void setType(final ExpressionType pType) {
        mType = pType;
    }
   
    public String getDescription() {
        return mDescription;       
    }
   
    public void setDescription(final String pDescription) {
        mDescription = pDescription;
    }
   
    @OneToMany(cascade = CascadeType.ALL)//, mappedBy = "expression")
    @IndexColumn(name = "expression_index", base=1)
    public List<ExpressionTarget> getExpressionTargets() {
        return mExpressionTargets;
    }
   
    public void setExpressionTargets(final List<ExpressionTarget> pExpressionTargets) {
        mExpressionTargets = pExpressionTargets;
    }
}


ExpressionTarget entity
Code:

@Entity
public class ExpressionTarget implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = -1658544469715177717L;
    private int mId;
    private int mRole;
    private TargetEntity mTargetEntity;
    private Expression mExpression; 
   
    public ExpressionTarget() { }
    public ExpressionTarget(int pPk, int pRole, TargetEntity pTargetEntity, Expression pExpression) {
        setId(pPk);
        setRole(pRole);
        setTargetEntity(pTargetEntity);
        setExpression(pExpression);
    }
   
    @Id
    public int getId() {
        return mId;
    }
   
    public void setId(final int pId) {
        mId = pId;
    }
   
    public int getRole() {
        return mRole;
    }
   
    public void setRole(final int pRole) {
        mRole = pRole;
    }
   
   
    @ManyToOne
    @JoinColumn(name = "targetEntity_id")
    public TargetEntity getTargetEntity() {
        return mTargetEntity;
    }
   
    public void setTargetEntity(final TargetEntity pTargetEntity) {
        this.mTargetEntity = pTargetEntity;
    }
   
    @ManyToOne
    @JoinColumn(name = "expression_id")
    public Expression getExpression() {
        return mExpression;
    }
   
    public void setExpression(final Expression pExpression) {
        mExpression = pExpression;
    }
}



TargetEntity entity
Code:

@Entity
public class TargetEntity implements Serializable {
   
    /**
     *
     */
    private static final long serialVersionUID = 1777950853877950863L;
    private int mId;
    private Class mClazz;
    private int mPk;
    private String mAttrName;
    private Target mTarget;   
    private List<ExpressionTarget> mExpressionTargets = new ArrayList<ExpressionTarget>();
    public String getAttrName() {
        return mAttrName;
    }
   
    public void setAttrName(String attrName) {
        mAttrName = attrName;
    }
   
    @Basic(optional = false)
    public Class getClazz() {
        return mClazz;
    }
   
    public void setClazz(Class pClazz) {
        mClazz = pClazz;
    }
   
    @Id   
    public int getId() {
        return mId;
    }
   
    public void setId(int pId) {
        mId = pId;
    }
   
    public int getPk() {
        return mPk;
    }
   
    public void setPk(int pPk) {
        mPk = pPk;
    }
   
    @Transient   
    public Target getTarget() {
        if(mTarget == null)
            mTarget = TargetFactory.createTarget(this);
       
        return mTarget;
    }

    @OneToMany(cascade = CascadeType.ALL)//, mappedBy = "targetEntity")
    @IndexColumn(name = "target_index", base=1)
    public List<ExpressionTarget> getExpressionTargets() {
        return mExpressionTargets;
    }
   
    public void setExpressionTargets(final List<ExpressionTarget> pExpressionTargets) {
        this.mExpressionTargets = pExpressionTargets;
    }
         
}


The simple query that i am trying to perform (worked when relations used mappedBy) is
Code:
Query tmpQuery = mEntityManager.createQuery("SELECT e.expression FROM TargetEntity " +
                "t INNER JOIN t.expressionTargets e " +
                "WHERE t.id = :pk AND e.expression.class = Rule").setParameter("pk", 1);

This produces the following SQL

Quote:
select expression3_.id as id1806_, expression3_.type as type1806_, expression3_.description as descript4_1806_, expression3_.expr as expr1806_, expression3_.DISCRIMINATOR as DISCRIMI1_1806_ from TargetEntity targetenti0_ inner join TargetEntity_ExpressionTarget expression1_ on targetenti0_.id=expression1_.TargetEntity_id inner join ExpressionTarget expression2_ on expression1_.expressionTargets_id=expression2_.id inner join expressionhierarchy expression3_ on expression2_.expression_id=expression3_.id where targetenti0_.id=? and expression3_.DISCRIMINATOR='rule'


Hibernate did not include the join needed between ExpressionTarget and expressionhierarchy_ExpressionTarget (this is an auto generated table, not a concreate entity). So do i have to actually set the Expression in ExpressionTarget with a .setExpression as in my opinion it would be bad in database terms (redundant data)?

The correct query should of been this

Quote:
select
expression3_.id as id1753_,
expression3_.type as type1753_,
expression3_.description as descript4_1753_,
expression3_.expr as expr1753_, expression3_.DISCRIMINATOR as DISCRIMI1_1753_
from TargetEntity targetenti0_
inner join TargetEntity_ExpressionTarget expression1_ on targetenti0_.id=expression1_.TargetEntity_id
inner join ExpressionTarget expression2_ on expression1_.expressionTargets_id=expression2_.id
inner join expressionhierarchy_ExpressionTarget expHiTar on expression2_.id=expHiTar.expressiontargets_id
inner join expressionhierarchy expression3_ on expHiTar.expressionhierarchy_id=expression3_.id
where targetenti0_.id=1 and expression3_.DISCRIMINATOR='rule'


Can anyone point out where i have gone wrong ?

Cheers,

Andy


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 13, 2006 7:47 am 
Senior
Senior

Joined: Tue Jul 25, 2006 9:05 am
Posts: 163
Location: Stuttgart/Karlsruhe, Germany
I decided that is was far too much trouble to have bi-directional indexed collections, as the bi-directionality does not work without the mapped by, and the indexed collection does not work with it (indexed never saved in the DB).

I have now implemented the collections as Sets, thus still allowing me to fetch multiple ones at the same time and avoiding the problems with indexed collections (can't be bi-directional).

Andy


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.