0 Replies Latest reply on Jul 25, 2013 1:35 PM by sunilpadda

    Envers is not respecting lazy one-to-one mapping

    sunilpadda

      Hello,

       

      I have two entities, Place and PlaceShape. PlaceShape is marked as a lazy one-to-one association and its working perfectly fine in Hibernate. However, when I edit Place (without loading PlaceShape) and commit the changes, Envers seems to loading PlaceShape to compute differences. It's not loading any one-to-many collections though. This is causing performance related issues, as PlaceShape is a huge entity and requires loading in specific circumstances. Call stacktrace, SQL log and Java code are mentioned below. Any help or suggestions are greatly appreciated.

       

      Thanks,

       

      Sunil

       

      Here is the stack-trace where the shape is getting fetched:

       

      Place.getPlaceShape(Place.java:160)
      at sun.reflect.GeneratedMethodAccessor361.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:601)
      at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:172)
      at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:175)
      at org.hibernate.envers.entities.mapper.MultiPropertyMapper.mapToMapFromEntity(MultiPropertyMapper.java:107)
      at org.hibernate.envers.synchronization.work.CollectionChangeWorkUnit.generateData(CollectionChangeWorkUnit.java:56)
      at org.hibernate.envers.synchronization.work.AbstractAuditWorkUnit.perform(AbstractAuditWorkUnit.java:72)
      at org.hibernate.envers.synchronization.AuditProcess.executeInSession(AuditProcess.java:114)
      at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:152)
      at org.hibernate.engine.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:543)
      at org.hibernate.engine.ActionQueue.beforeTransactionCompletion(ActionQueue.java:216)
      at org.hibernate.impl.SessionImpl.beforeTransactionCompletion(SessionImpl.java:571)
      at org.hibernate.jdbc.JDBCContext.beforeTransactionCompletion(JDBCContext.java:250)
      at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:138)
      at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
      

       

      Here is the SQL log for the operation described above:

       

      select place0_.PID as PID1_10_6_, place0_.NAME as NAM2_10_6_ from PLACE place0_ where place0_.PID=?;
      update PLACE (NAME) values (?);
      select hibernate_sequence.nextval from dual;
      select placeshape0_.SPATIAL_ID as SPATIAL1_19_7_, placeshape0_.PID as PID3_19_7_, placeshape0_.SHAPE as SHAPE19_7_, place1_.PID as PID1_10_0_, place1_.NAME as NAM2_10_0_ from PLACE_SHAPE placeshape0_ left outer join PLACE place1_ on placeshape0_.PID=place1_.PID where placeshape0_.PID=?;
      insert into Revinfo (log, revtstmp, username, rev) values (?, ?, ?, ?);
      insert into PLACE_AUD (REVTYPE, NAME, PID, REV) values (?, ?, ?, ?);
      

      Here is the code for the entities:

       

      @Entity
      @Audited
      @Table(name = "PLACE")
      public class Place implements FieldHandled {
          private long pid;
          private String name; 
          private PlaceShape placeShape;
          private FieldHandler fieldHandler;
          @Id
          @Column(name = "PID", columnDefinition = "NUMBER(10,0)", nullable = false)
          public long getPid() {
              return pid;
          }
      
          public void setPid(long pid) {
              this.pid = pid; 
          }
         
          @Column(name = "NAME", columnDefinition = "NVARCHAR(100)", nullable = true)
           public String getName() {
               return name;
           }
      
          public void setName(String name) {
               this.name = name;
           }
      
          @OneToOne(mappedBy = "place", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, optional = true)
          @LazyToOne(value = LazyToOneOption.NO_PROXY)
          public PlaceShape getPlaceShape() {
              if (fieldHandler != null) {
                  return (PlaceShape) fieldHandler.readObject(this, "placeShape", placeShape);
              }
              return placeShape;
          }
      
          public void setPlaceShape(PlaceShape placeShape) {
              if (fieldHandler != null) {
                  this.placeShape = (PlaceShape) fieldHandler.writeObject(this, "placeShape", this.placeShape, placeShape);
                  return;
              }
              this.placeShape = placeShape;
          }
      }
      
      @Audited
      @Entity
      @Table(name = "PLACE_SHAPE")
      public class PlaceShape implements Serializable {
          private long id;
          private Place place;
          private Geometry shape;
      
          @Id
          @SequenceGenerator(name = "SEQ_STORE", sequenceName = "SPATIAL_SEQ", allocationSize = 1)
          @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STORE")
          @Column(name = "SPATIAL_ID", columnDefinition = "NUMBER(10, 0)", nullable = false)
          public long getId() {
              return id;
          }
      
          public void setId(long id) {
              this.id = id;
          }
      
          @OneToOne(fetch = FetchType.EAGER)
          @JoinColumn(name = "PID", referencedColumnName = "PID")
          public Place getPlace() {
              return place;
          }
      
          public void setPlace(Place place) {
              this.place = place;
          }
      
          @Type(type = "org.hibernatespatial.GeometryUserType")
          @Column(name = "SHAPE", columnDefinition = "MDSYS.SDO_GEOMETRY", nullable = false)
          public Geometry getShape() {
              return shape;
          }
      
          public void setShape(Geometry shape) {
              this.shape = shape;
          }
      }