-->
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.  [ 2 posts ] 
Author Message
 Post subject: @OneToMany delete of dependancies removed from cache
PostPosted: Wed Feb 13, 2008 11:23 am 
Beginner
Beginner

Joined: Fri Apr 20, 2007 10:48 am
Posts: 49
Location: France
Hibernate version:any

Problems with Session and transaction handling?
I have Read this: http://hibernate.org/42.html

Hi I have a problem when I merge an entity with a modified One to many relationship : removed entries in the many side are not deleted (even if I use the same PersistentSet created by hibernate when reading). But this is not the subject:

I have created a utility class that I would like to use as a @PreUpdate inerceptor. The class simply compares the current state of the enity dependency with the one in db and removes the unwanted entries in db (with a single delete sql).

My only problem is that it's impossible for me to join the existing transaction from inside the interceptor. Is there a way to do that?

here's my code for the deletion but it's not relevant to the undersanding of the need.


Code:
package fr.into.common.jpa;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.Query;

import com.sun.org.apache.commons.beanutils.BeanUtils;

import fr.into.common.util.DataUtil;
import fr.into.common.util.data.BasicItem;
import fr.into.common.util.data.collections.CollectionsHelper;

/**
* Should be used to handle One to many relationships deletion on update of a
* parent.
*
* @author Zied Hamdi for Into© corporation on 13 févr. 08
*
* www.into-i.fr
*/
public class JPAUtil {

   private static class IdExtractor<T>
         implements Comparator<T> {
      protected Method   idGetter;
      protected Field      idField;
      private Object[]   getterArgs   = {};
      private String      propertyName;

      @SuppressWarnings("unchecked")
      public IdExtractor(T first) {
         idGetter = findIdGetter( (Class<T>) first.getClass() );
         if( idGetter == null ) {
            idField = findIdField( (Class<T>) first.getClass() );
            if( idField == null )
               throw new IllegalArgumentException( "Class " + first.getClass().getName() + " is not an entity: can't find id field or property." );

            idField.setAccessible( true );
            propertyName = idField.getName();
         }
         propertyName = idGetter.getName().substring( 3, 4 ).toLowerCase() + idGetter.getName().substring( "getX".length() );
      }

      public String getPropertyName() {
         return propertyName;
      }

      public Object getId(T entry) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
         if( idGetter != null )
            return idGetter.invoke( entry, getterArgs );
         return idField.get( entry );
      }

      public Method findIdGetter(Class<T> clazz) {
         Method[] methods = clazz.getMethods();
         for( Method method : methods ) {
            Annotation[] ann = method.getAnnotations();
            for( Annotation annotation : ann ) {
               if( annotation.annotationType().equals( Id.class ) )
                  return method;
            }
         }
         return null;
      }

      public Field findIdField(Class<T> clazz) {
         Field[] fields = clazz.getFields();
         for( Field field : fields ) {
            Annotation[] ann = field.getAnnotations();
            for( Annotation annotation : ann ) {
               if( annotation.annotationType().equals( Id.class ) )
                  return field;
            }
         }
         return null;
      }

      public int compare(T o1, T o2) {
         try {
            return DataUtil.areEqual( getId( o1 ), getId( o2 ) ) == true ? 0 : 1;
         } catch( Exception ex ) {
            throw new RuntimeException( ex );
         }
      }

   }

   /**
    * Deletes elements that are in newValues and not in dbValues. Existence of an
    * element is determined by comparing fields anotated with {@link Id}
    *
    * @author Zied Hamdi for Into© corporation on 13 févr. 08
    * @param <T>
    * @param dbValues
    * @param newValues
    * @param em
    * @return
    * @throws IllegalArgumentException
    * @throws IllegalAccessException
    * @throws InvocationTargetException
    */
   public static <T> List<T> deletePrivatelyOwned(Collection<T> dbValues, Collection<T> newValues, BasicItem<String, Object> parent, EntityManager em)
         throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
      return deletePrivatelyOwned( dbValues, newValues, parent, null, em );
   }

   /**
    * Deletes elements that are in newValues and not in dbValues. Existence of an
    * element is determined by {@link Comparator#compare(Object, Object)} (if it
    * returns 0 then the element is considered as existing). If comparator is
    * null, an id comparison is made.
    *
    * @author Zied Hamdi for Into© corporation on 13 févr. 08
    * @param <T>
    * @param dbValues
    * @param newValues
    * @param comparator
    * @param em
    * @return
    * @throws IllegalArgumentException
    * @throws IllegalAccessException
    * @throws InvocationTargetException
    */
   @SuppressWarnings("unchecked")
   public static <T> List<T> deletePrivatelyOwned(Collection<T> dbValues, Collection<T> newValues, BasicItem<String, Object> parent, Comparator<T> comparator, EntityManager em)
         throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
      if( dbValues == null || dbValues.size() == 0 )
         return null;
      if( newValues == null )
         throw new IllegalArgumentException( "newValues can't be null" );

      T first = dbValues.iterator().next();
      StringBuffer sql = new StringBuffer( "DELETE " + first.getClass().getSimpleName() );
      sql.append( " t WHERE" );
      sql.append( " t." + parent.getKey() + "=:parentId" );

      if( newValues.size() == 0 ) {
         Query query = em.createQuery( sql.toString() );
         query.setParameter( "parentId", parent.getValue() );
         query.executeUpdate();
         return new ArrayList<T>( dbValues );
      }

      IdExtractor<T> idExtractor = new IdExtractor<T>( first );

      List<T> toDelete = CollectionsHelper.negativeFilter( dbValues, newValues, comparator != null ? comparator : idExtractor );
      if( toDelete.size() == 0 )
         return null;

      sql.append( " AND" );

      String propertyName = idExtractor.getPropertyName();
      int counter = 0;
      for( ; counter < toDelete.size(); counter++ ) {
         sql.append( " t." + propertyName + "=:value" + counter + " OR" );
      }
      Query query = em.createQuery( sql.substring( 0, sql.length() - " OR".length() ) );
      counter = 0;
      for( T entry : toDelete ) {
         query.setParameter( "value" + counter++, idExtractor.getId( entry ) );
      }
      query.setParameter( "parentId", parent.getValue() );
      query.executeUpdate();

      return (List<T>) toDelete;
   }

   public static void deletePrivatelyOwned(Object entity, String oneToManySetProperty, EntityManager em) {
      throw new UnsupportedOperationException();
   }

   /**
    * Unused...
    *
    * @author Zied Hamdi for Into© corporation on 13 févr. 08
    * @param entity
    * @param property
    * @param depth
    * @return
    * @throws IllegalAccessException
    * @throws InvocationTargetException
    * @throws NoSuchMethodException
    */
   public Object getBeanPropertyValue(Object entity, String property, int depth) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
      if( entity == null )
         throw new IllegalArgumentException( "Bean can't be null" );

      int indexOfLocalProperty = property.indexOf( "." );
      String localProperty;
      if( indexOfLocalProperty == -1 ) {
         localProperty = property;
      } else {
         localProperty = property.substring( 0, indexOfLocalProperty );
      }

      if( depth == 0 )
         return BeanUtils.getSimpleProperty( entity, localProperty );

      return getBeanPropertyValue( entity, property.substring( indexOfLocalProperty + 1 ), depth - 1 );
   }

}


Regards,
Zied Hamdi

_________________
Regards,
Zied Hamdi


Top
 Profile  
 
 Post subject: How does hibernate get generics info targetEntity from .clas
PostPosted: Wed Feb 13, 2008 12:49 pm 
Beginner
Beginner

Joined: Fri Apr 20, 2007 10:48 am
Posts: 49
Location: France
Hi,

I have a big question !!!

How does hibernate get generics info targetEntity from compiled .class files?

In fact I need to get that info to get my Utility class work. Suddenly I realized it's not possible to get the info from a compiled class. This leads me to the question: how can a ear file work does hibernate replicate the info on deployement and put it somewhere in the ear???

Code:
   private class ParentEntityParser {
      protected Field      field;
      protected String   mappedBy;
      // protected ParentEntityParser inner;
      protected Object   value;
      @SuppressWarnings("unchecked")
      protected Class      targetEntity;

      public ParentEntityParser(Object entity, String property, int depth) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
         getBeanPropertyValue( entity, property, depth );
      }

      /**
       * Unused...
       *
       * @author Zied Hamdi for Into© corporation on 13 févr. 08
       * @param entity
       * @param property
       * @param depth
       * @return
       * @throws IllegalAccessException
       * @throws InvocationTargetException
       * @throws NoSuchMethodException
       */
      public void getBeanPropertyValue(Object entity, String property, int depth) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
         if( entity == null )
            throw new IllegalArgumentException( "Bean can't be null" );

         int indexOfLocalProperty = property.indexOf( "." );
         String localProperty;
         if( indexOfLocalProperty == -1 ) {
            localProperty = property;
         } else {
            localProperty = property.substring( 0, indexOfLocalProperty );
         }

         Field[] fields = entity.getClass().getFields();
         for( Field field : fields ) {
            if( field.getName().equals( localProperty ) ) {
               this.field = field;
               field.setAccessible( true );
               Annotation[] annotations = field.getAnnotations();
               for( Annotation annotation : annotations ) {
                  if( annotation.annotationType().equals( OneToMany.class ) ) {
                     OneToMany oneToMany = (OneToMany) annotation;
                     mappedBy = oneToMany.mappedBy();
                     targetEntity = oneToMany.targetEntity();
                     break;
                  }
               }
               if( targetEntity == null ) {
                  Type type = field.getGenericType();
// too late: the class doesn't contain the info
               }
               break;
            }
         }
         this.value = field.get( entity );
         // inner = new ParentEntityParser( value, property.substring(
         // indexOfLocalProperty + 1 ), depth - 1 );
      }

      public Field getField() {
         return field;
      }

      public void setField(Field field) {
         this.field = field;
      }

      public String getMappedBy() {
         return mappedBy;
      }

      public void setMappedBy(String mappedBy) {
         this.mappedBy = mappedBy;
      }

      public Object getValue() {
         return value;
      }

      public void setValue(Object value) {
         this.value = value;
      }

      public Class getTargetEntity() {
         return targetEntity;
      }

      public void setTargetEntity(Class targetEntity) {
         this.targetEntity = targetEntity;
      }
   }


Any suggestion will be highly appreciated.

_________________
Regards,
Zied Hamdi


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 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:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.