Announcement Announcement Module
Collapse
No announcement yet.
initializing hibernate many-to-one relation within Set Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • initializing hibernate many-to-one relation within Set

    Hi,
    I posted the same issue on the hibernate site, but am cross-posting here because it may be spring that I'm getting into difficulty with.
    I'm having some difficulty getting a many-to-one relation initialized. I'm subclassing HibernateDaoSupport class in the class involved.
    What I have is a Batch that contains a Set of transactions. In a certain method I want to load a batch using hibernate by calling the getHibernateTemplate().findByNamedParam() method, passing in the id of the batch. I also need the set of transactions in this case, which I get back by doing a left join fetch in the hql passed in to the spring method mentioned (this is the reason I use hql - I need to specify a left join fetch)
    This all works fine. However here I get into trouble. Each Transaction has 2 many-to-one relations (a transactionCurrency and an errorCode) that I want initialized by this query. I thought the best way to do this was by iterating through the transactions and calling a Hibernate.initialize() for each many-to-one I was interested in initializing. However this seems only to work for the transactionCurrency many-to-one (even though the hibernate-generated select SQL for both many-to-ones appears on the console).
    The code snippet below uses a hardcoded transactional callback. I've tried using a TransactionProxyFactoryBean as well with the same results.
    The errorCode object is always a cglib proxy with null values for both its fields. I'm sure I'm doing something stupid here or there is a trivial mistake in my mappings or transaction. I'd be grateful if anyone could point any problem out, cause I can't see it.
    Here's the spring code
    Code:
        public Batch getBatchWithTransactions(final Long batchID) {
            return (Batch) getHibernateTemplate().execute(new
    HibernateCallback() {
                public Object doInHibernate(final Session session) {
                    Batch batch =  (Batch) session.createQuery(
                            "from myproject.dataobject.Batch b "
                            + "left join fetch b.transactions "
                            + "where b.id
    = :batchID").setParameter("batchID", batchID)
                            .list().get(0);
                    Iterator txns = batch.getTransactions().iterator();
                    while (txns.hasNext()) {
                        Transaction t = (Transaction) txns.next();
                        Hibernate.initialize(t.getErrorCode());
                        Hibernate.initialize(t.getTransactionCurrency());
                    }
                    return batch;
                }
            });
        }

    (relevant parts of 4 different hbm.xml files)
    Batch.hbm.xml
    Code:
    <hibernate-mapping>
         <class name="myproject.dataobject.Batch"
           table="batch">
             <id name="id"
                column="batch_id" type="long">
                 <generator class="native" />
             </id>
            <set name="transactions" inverse="true" cascade="save-update">
                <key column="batch_id" />
                <one-to-many class="myproject.dataobject.Transaction" />
            </set>
         </class>
    </hibernate-mapping>
    transaction.hbm.xml
    Code:
    <hibernate-mapping package="myproject.dataobject">
        <class name="Transaction" table="TRANSACTION">
            <id
                column="TRANSACTION_ID"
                name="id"
                type="long"
                >
                <generator class="native" />
            </id>
            <many-to-one name="batch"
                not-null="true"
                class="myproject.dataobject.Batch"
                cascade="save-update"
                >
                <column name="BATCH_ID" />
            </many-to-one>
            <many-to-one name="errorCode"
                class="myproject.dataobject.lookup.StatusCode"
                column="ERROR_CODE"
                />
            <many-to-one name="transactionCurrency"
                class="myproject.dataobject.Currency"
                column="TRANSACTION_CURRENCY_CODE"
                />
        </class>
    </hibernate-mapping>
    StatusCode.hbm.xml
    Code:
    <hibernate-mapping package="myproject.dataobject">
       <class name="StatusCode" table="STATUS_CODE">
          <id
             column="ERROR_CODE"
             name="id"
             type="integer"
          >
             <generator class="native" />
          </id>
          <property
             column="ERROR_DESCRIPTION"
             length="50"
             name="description"
             not-null="false"
             type="string"
           />
       </class>
    </hibernate-mapping>
    Currency.hbm.xml
    Code:
    <hibernate-mapping>
      <class name="myproject.dataobject.Currency"
          table="currency">
          <id name="isoCode" column="iso_code" type="integer">
              <generator class="sequence">
                  <param name="sequence">acquirer_comm_seq</param>
              </generator>
          </id>
          <property name="swiftCode"
              column="swift_code"
              not-null="true"
              type="string"
              unique="false"
              />
          <property name="name"
              column="description"
              not-null="true"
              type="string"
              unique="false"
              />
          <property name="minorUnits"
              column="minor_units"
              not-null="true"
              type="integer"
              unique="false"
              />
      </class>
    </hibernate-mapping>

  • #2
    Found the problem. getters in the offending unpopulated object were marked as final, which meant that hibernate could not proxy them.

    Comment


    • #3
      As a work around specify inside the mapping the access to be directly on the field (thus bypassing the getter/setter).

      Comment


      • #4
        BTW: If you tell Hibernate to populate the field, how does Hibernate do dirty detection?

        Comment


        • #5
          That's something internal to Hibernate; AFAIK the proxy will not override the method and will do field interception (as opposed to method interception).

          Comment


          • #6
            (OFF TOPIC)

            (OFF TOPIC): I see. I assumed (actually guessed ) that hibernate overrode the accessors and set a dirty flag on the setters.

            I suppose it must be a bit more sophisticated.

            Thanks dude

            Comment

            Working...
            X