Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Lazy load on OneToMany mapping does not work
Lazy load on OneToMany mapping does not work [message #644899] Tue, 14 December 2010 16:37 Go to next message
Matti Hansson is currently offline Matti HanssonFriend
Messages: 68
Registered: July 2009
Member
Hi!
I'm using EclipseLink 1.1.4 to map a relationship where an "AreaSurface" can belong to several "Area". By querying Area by id I get the Area and its AreaSurface, but if I use a geometry query I get the AreaSurface but not its Areas. The log shows that a database query is prepared
[EL Fine]: ClientSession(15830327)--Connection(29407392)--SELECT FKFOGGUID, FNR_FR, AREANR FROM AREA WHERE (FKFOGGUID = ?)
	bind => [859269b6-5200-49ab-b47f-785c4c305d4d]

but never executed. I do get the Areas if I set the OneToMany mapping in AreaSurface to eager. Any idea what may be wrong?

Here are the classes:
@Entity
public class AreaSurface {
  
  @Id
  @Column(name = "GUID")
  private String uuid;
  
  @StructConverter(name = "GeometryConverter",
      converter = ConverterType.GEOMETRY_CONVERTER)
  @Convert("GeometryConverter")
  @Column(name = "SHAPE", columnDefinition = "MDSYS.SDO_GEOMETRY", nullable = false)
  private Geometry geometry;
  
  @OneToMany(mappedBy = "areaSurface") //if fetch = FetchType.EAGER is set it works
  private List<Area> areas;

  // Getters and setters..
  
}

@Entity
public class Area{
  
  @Id
  @Column(name = "FKFOGGUID")
  private String fkfogguid;
  
  @Column(name = "FNR_FR", insertable = false, updatable = false)
  private String areaId;
  
  @Column(name = "AREANR")
  private int areaNumber;
  
  @ManyToOne()
  @JoinColumn(name = "FKFOGGUID", referencedColumnName = "GUID", insertable = false, updatable = false)
  private AreaSurface areaSurface;
  
  // ...
  
}
Re: Lazy load on OneToMany mapping does not work [message #645104 is a reply to message #644899] Wed, 15 December 2010 15:29 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

The log is showing the query being executed, not prepared.

Please include the code and query you are executing.

If something is lazy, it will not be instantiated until accessed. If you serialize the object before access, then it will be null or trigger an error.

If the object was already in the cache, then you will get the cached object back.


James : Wiki : Book : Blog : Twitter
Re: Lazy load on OneToMany mapping does not work [message #645155 is a reply to message #645104] Wed, 15 December 2010 17:44 Go to previous messageGo to next message
Matti Hansson is currently offline Matti HanssonFriend
Messages: 68
Registered: July 2009
Member
Quote:
The log is showing the query being executed, not prepared.

Does it really? I attached some more logs, and as you can see the eager log has the line "Execute query ReadObjectQuery(name="areaSurface" referenceClass=AreaSurface )" while the lazy log skips straight to "release unit of work".

Eager log:
[EL Finest]: UnitOfWork(3966697)--Execute query ReadAllQuery(referenceClass=AreaSurface )
[EL Finest]: ClientSession(32314330)--Execute query ReadAllQuery(referenceClass=AreaSurface)
[EL Fine]: ClientSession(32314330)--Connection(5511938)--SELECT GUID, SHAPE FROM AREA_SURFACE WHERE ((MDSYS.SDO_FILTER(SHAPE, ?, ?) = ?) AND (MDSYS.SDO_RELATE(SHAPE, ?, ?) = ?))
	bind => [JGeometry (gtype=1, dim=2, srid=3006, QUERYTYPE=WINDOW, TRUE, JGeometry (gtype=1, dim=2, srid=3006, MASK=ANYINTERACT QUERYTYPE=WINDOW, TRUE]
[EL Finest]: ClientSession(32314330)--Execute query ReadAllQuery(name="areas" referenceClass=Area sql="SELECT FKFOGGUID, FNR_FR, AREANR FROM AREA WHERE (FKFOGGUID = ?)")
[EL Fine]: ClientSession(32314330)--Connection(5511938)--SELECT FKFOGGUID, FNR_FR, AREANR FROM AREA WHERE (FKFOGGUID = ?))
	bind => [859269b6-5200-49ab-b47f-785c4c305d4d]
[EL Finest]: ClientSession(32314330)--Execute query ReadObjectQuery(name="areaSurface" referenceClass=AreaSurface )
[EL Finer]: UnitOfWork(3966697)--release unit of work
[EL Finer]: ClientSession(32314330)--Connection(5511938)--rollback transaction
[EL Finer]: ClientSession(32314330)--client released


Lazy log:
[EL Finest]: UnitOfWork(26193147)--Execute query ReadAllQuery(referenceClass=AreaSurface )
[EL Finest]: ClientSession(32579087)--Execute query ReadAllQuery(referenceClass=AreaSurface )
[EL Fine]: ClientSession(32579087)--Connection(27595538)--SELECT GUID, SHAPE FROM AREA_SURFACE WHERE ((MDSYS.SDO_FILTER(SHAPE, ?, ?) = ?) AND (MDSYS.SDO_RELATE(SHAPE, ?, ?) = ?))
	bind => [JGeometry (gtype=1, dim=2, srid=3006, QUERYTYPE=WINDOW, TRUE, JGeometry (gtype=1, dim=2, srid=3006, MASK=ANYINTERACT QUERYTYPE=WINDOW, TRUE]
[EL Finest]: ServerSession(22238933)--Execute query ReadAllQuery(name="areas" referenceClass=Area )
[EL Finest]: ServerSession(22238933)--reconnecting to external connection pool
[EL Fine]: ServerSession(22238933)--Connection(1399004)--SELECT FKFOGGUID, FNR_FR, AREANR FROM AREA WHERE (FKFOGGUID = ?))
	bind => [859269b6-5200-49ab-b47f-785c4c305d4d]
[EL Finer]: UnitOfWork(26193147)--release unit of work
[EL Finer]: ClientSession(32579087)--Connection(27595538)--rollback transaction
[EL Finer]: ClientSession(32579087)--client released
[EL Finer]: ServerSession(22238933)--client acquired
[EL Finer]: ClientSession(5174832)--Connection(322649)--begin transaction

java.lang.AssertionError: expected:<1> but was:<0>
	at org.junit.Assert.fail(Assert.java:74)
	at org.junit.Assert.failNotEquals(Assert.java:448)
	...


Here is the unit test:
  @Test
  public void findAreaByPointInAreaSurface() {
    Point point = new GeometryFactory(new PrecisionModel(),3006).createPoint(new Coordinate(6598735, 714690));
    List<AreaSurface> surfaces = repository.findSurfacesByGeometry(point, AreaSurface.class);
    assertEquals(1, surfaces.size());
    AreaSurface surface = surfaces.get(0);
    assertNotNull(surface.getAreas());
    assertEquals(1, surface.getAreas().size()); // <-- fails if lazy!
    Area area = surface.getAreas().get(0);
    ...


And this is the query code:
  public List<AreaSurface> findSurfacesByGeometry(Geometry geometry, Class clazz) {
    ReadAllQuery query = new ReadAllQuery(clazz);
    query.setIsReadOnly(true);
    ExpressionBuilder builder = query.getExpressionBuilder();
    
    SpatialParameters spatialParameters = new SpatialParameters();
    spatialParameters.setQueryType(SpatialParameters.QueryType.WINDOW);
    
    SpatialParameters spatialParameters2 = new SpatialParameters();
    spatialParameters2.setQueryType(SpatialParameters.QueryType.WINDOW);
    
    SpatialParameters.Mask [] mask;
    
    if(geometry instanceof Polygon || geometry instanceof MultiPolygon) {
      mask = new SpatialParameters.Mask [] {
              SpatialParameters.Mask.EQUAL,
              SpatialParameters.Mask.OVERLAPBDYDISJOINT,
              SpatialParameters.Mask.OVERLAPBDYINTERSECT,
              SpatialParameters.Mask.CONTAINS,
              SpatialParameters.Mask.COVERS,
              SpatialParameters.Mask.INSIDE,
              SpatialParameters.Mask.COVEREDBY,
              SpatialParameters.Mask.ON
      };      // Basically ANYINTERACT - TOUCH.
    } else {
      mask = new SpatialParameters.Mask [] {
              SpatialParameters.Mask.ANYINTERACT
      };
    }
    
    spatialParameters2.setMasks(mask);

    JGeometry jgeometry = GeometryConverter.toJGeometry(geometry);
    Expression filter = SpatialExpressionFactory.filter(builder.get("geometry"), jgeometry, spatialParameters);
    Expression relate = SpatialExpressionFactory.relate(builder.get("geometry"), jgeometry, spatialParameters2);
    
    Expression spatialCriteria = filter.and(relate);
    query.setSelectionCriteria(spatialCriteria);
    
    return (List<AreaSurface>) entityManager.getActiveSession().executeQuery(query);
  }


Thanks alot!
Re: Lazy load on OneToMany mapping does not work [message #645321 is a reply to message #645155] Thu, 16 December 2010 16:01 Go to previous messageGo to next message
Matti Hansson is currently offline Matti HanssonFriend
Messages: 68
Registered: July 2009
Member
I made a working example that illustrates the problem:

http://uploading.com/files/7dc9f1f5/area.zip/

The second test in AreaRepositoryTest.java fails.
The tables are described in src/test/sql/create.sql
Re: Lazy load on OneToMany mapping does not work [message #645741 is a reply to message #645321] Mon, 20 December 2010 11:09 Go to previous messageGo to next message
Matti Hansson is currently offline Matti HanssonFriend
Messages: 68
Registered: July 2009
Member
Some further finds: I added an ID query to AreaSurface and when using that, the lazy load works just fine. It seems the problem only occurs when performing a spatial query. I've been using JTS Geometry in my code so I switched to Oracle's JGeometry, but that had no effect.
I'll keep poking around. Any ideas, please let me know.
Thanks!
Re: Lazy load on OneToMany mapping does not work [message #645935 is a reply to message #645741] Tue, 21 December 2010 09:27 Go to previous messageGo to next message
Matti Hansson is currently offline Matti HanssonFriend
Messages: 68
Registered: July 2009
Member
I'm giving up. I haven't found a way to make spatial queries and lazy loading work together so the workaround has been to do the spatial query and then use the results to make an id query. Inefficient but at least it solves the problem.

  public List<AreaSurface> findSurfacesByGeometry(JGeometry geometry, Class clazz) {
    ReadAllQuery query = new ReadAllQuery(clazz);
    query.setIsReadOnly(true);
    ExpressionBuilder builder = query.getExpressionBuilder();
    
    SpatialParameters spatialParameters = new SpatialParameters();

    // Spatial stuff...
    
    List<AreaSurface> surfaces = (List<AreaSurface>) entityManager.getActiveSession().executeQuery(query);
    
    // Make id query in order to get lazy loading to work.
    if(surfaces.size() > 0) {
      String[] uuids = new String[surfaces.size()];
      for(int i = 0; i<uuids.length; i++) {
        uuids[i] = surfaces.get(i).getUuid();
      }
    
      query = new ReadAllQuery(clazz);
      builder = query.getExpressionBuilder();
      Expression expression = builder.get("uuid").in(uuids);
      query.setSelectionCriteria(expression);
      return (List<AreaSurface>) entityManager.getActiveSession().executeQuery(query);
    } else {
      return surfaces;
    }
  }
Re: Lazy load on OneToMany mapping does not work [message #647120 is a reply to message #645935] Tue, 04 January 2011 16:35 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Note that you first query uses readOnly and the second does not. Perhaps this is related to your issue.

Ensure that you are always maintaining bi-directional references, and are not corrupting the objects in your cache.


James : Wiki : Book : Blog : Twitter
Re: Lazy load on OneToMany mapping does not work [message #647134 is a reply to message #647120] Tue, 04 January 2011 17:21 Go to previous message
Matti Hansson is currently offline Matti HanssonFriend
Messages: 68
Registered: July 2009
Member
Thank you for your reply, James!
You are quite right about the readOnly configuration. If I set the second query to readOnly, the lazy load fails in the same way as before. However, removing readOnly from the geometry query does not fix the problem, and the second query is still required. Sad
Previous Topic:CacheRetrieveMode.BYPASS of EclipseLink is not useful.
Next Topic:How can I query all past versions of an object with eclipselink?..
Goto Forum:
  


Current Time: Sat Dec 20 01:44:27 GMT 2014

Powered by FUDForum. Page generated in 0.03221 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software