Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] EclipseLink 2.2 is calling size() on LAZY fetched OneToMany mapping Set

Hello Patric,

Can you explain what you mean by:
>- only call size() on an IndirectSet (or other collection indirections) if its delegation container with the real entities has previously been fetched. (otherwise use NoIndirectionPolicy) My understanding of the code involved is that it is only triggering the indirect collection on the refreshed entity if the collection was previously fetched. Did you mean something different?

Best Regards,
Chris

On 23/05/2011 11:57 AM, Patric Rufflar wrote:
Hi Tom,

a small update on this topic:
The refresh query hint is definitely required to reproduce the issue.
Without the hint, size() will not be called on the IndirectSet.

In my opinion, EclipseLink should
- only call size() on an IndirectSet (or other collection indirections) if its delegation container with the real entities has previously been fetched. (otherwise use NoIndirectionPolicy)
- should not call size() / resolve indirect OneToMany Sets recursively

As an result the refresh query hint behavior would match the EntityManager.refresh() and
prior EclipseLink releases again.

Regards,
Patric


Quoting Patric Rufflar <patric@xxxxxxxxxxx>:

Hi Tom,

you're right, during anonymizing the names I got confused as well and used the wrong name, rev, instead of the inner object, rev2. Of course the query is:

SELECT rev FROM MyEntity rev WHERE rev.MyEntityPK_.idPart1_ = ?1
AND rev.MyEntityPK_.idPart2_=(SELECT MAX(rev2.MyEntityPK_.idPart2_)
FROM MyEntity rev2 WHERE rev2.MyEntityPK_.idPart1_ = ?1)

Please note, that I am using a Set as the OneToMany Collection.
Maybe this matters as well, I haven't tried it with a List.

I am not sure if I understood you correctly what you mean with "what does the code that executes the query look like", the code simply does the following:

- Prepare the query string
- Invokes EntityManager.createQuery(String)
- adds the two mentioned query hints
- binds the value
- calls query.getSingleResult() which ends up in the situation which I described

I'll apolgize but I'm not sure if  I got the point in your last section.
Before executing the query some other operations are made, which might be relevant to reproduce this behavior. I am going to figure out if these operations are really neccessary for reproducing that case.

BTW: Which regular use case requires to call CollectionContainerPolicy.sizeFor(Object) (which will call size() in the IndirectSet)?

Patric

Zitat von Tom Ware <tom.ware@xxxxxxxxxx>:

Although the query is a bit strange, I was able to run a comparable one on a comparable set of mappings on our test framework. I am not seeing the call to instantiate the list.

What does the code that executes the query look like? (if the query is not defined as part of that code, what does the declaration look like?)

One thing I can do to make the query instantiate the list is to add or remove from the list elsewhere in the persistence context. 'any change that is happening?

Note: I am currently running on the code from our latest 2.3 nightly. I hope to have time to move my test case to our 2.2 release soon.

-Tom

Tom Ware wrote:
Hi Patric,

I'm a bit confused about your query. The inner select's where clause doesn't seem to reference the object being selected in the inner select. What are you trying to get out of this query?

-Tom

Patric Rufflar wrote:
Hi Tom,

the query is the following:
(I anonymized all names)

SELECT rev FROM MyEntity rev WHERE rev.MyEntityPK_.idPart1_ = ?1 AND rev.MyEntityPK_.idPart2_=(SELECT MAX(rev2.MyEntityPK_.idPart2_) FROM MyEntity rev2 WHERE rev.MyEntityPK_.idPart1_ = ?1)

MyEntity is the entity named A below

ManyToOne Mapping from MyEntity to entity B

@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumns({
@JoinColumn(name="ID_PART_1",referencedColumnName="ID_PART_1"),
@JoinColumn(name="ID_PART_2",referencedColumnName="ID_PART_2")
})
private B b_;

The OneToMany Mapping from entity B to C is:

@OneToMany(mappedBy="b_",
cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH} )
private Set<C> cSet_;


(there are other mappings defined in A and B, but I don't think that these are relevant here)
Two Query hints are used: REFRESH = true, FLUSH = false
Pessimistic locking is not used.

Please note, that the same query, using the same entities with the same data is not showing the problem when using EclipseLink 1.1/2.1.

Thanks,
Patric


Zitat von Tom Ware <tom.ware@xxxxxxxxxx>:

Hi Patric,

What does your query look like?  What do your mappings look like?

The code that would instantiate the object runs in a couple of cases.

1. some cases where the query is doing a refresh and the relationship was already populated in the persistence context
2. The object is joined or fetch joined in the query
3. Some pessimistic-locking related cases

-Tom

Patric Rufflar wrote:
Hi,

I encountered a situation which I cannot explain.
Maybe somebody can help me out.

I'm trying to fetch an entity of class A via Query, which has a ManyToOne mapping to an entity of class B which has a OneToMany mapping (using an IndirectSet) to entities of class C.

I am not providing a FetchType, so I expect the default LAZY.
Weaving is not used.

As you can see in the stacktrace below (line marked with >>>), EclipseLink calls size() on the IndirectSet which causes that the actual entities of the indirection collection will be fetched, which of course is not desired. (in my case there are 10000 of entities in that Set which have additional references to other entities which causes my application to stop working)

In EclipseLink 2.1 and 1.1.x I cannot see this behavior.

My question:
- Is this an expected behavior?
- If so: How can I force EclipseLink to not call size() on the IndirectSet?

Thank you and best regards,
Patric

Here's the important part of the stackstrace:
...
RepeatableWriteUnitOfWork(UnitOfWorkImpl).getCommitManager() line: 1854 UnitOfWorkQueryValueHolder(UnitOfWorkValueHolder).instantiateImpl() line: 152 UnitOfWorkQueryValueHolder(UnitOfWorkValueHolder).instantiate() line: 222
UnitOfWorkQueryValueHolder(DatabaseValueHolder).getValue() line: 88
IndirectSet.buildDelegate() line: 192
IndirectSet.getDelegate() line: 343
IndirectSet.size() line: 500
CollectionContainerPolicy.sizeFor(Object) line: 177
TransparentIndirectionPolicy.instantiateObject(Object, Object) line: 369 OneToManyMapping(ForeignReferenceMapping).buildCloneFromRow(AbstractRecord, JoinedAttributeManager, Object, CacheKey, ObjectBuildingQuery, UnitOfWorkImpl, AbstractSession) line: 280 ObjectBuilder.buildAttributesIntoWorkingCopyClone(Object, CacheKey, ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, boolean) line: 1415 ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object) line: 1561 ObjectBuilder.buildObjectInUnitOfWork(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object, ClassDescriptor) line: 561 ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, JoinedAttributeManager) line: 497 ObjectBuilder.buildObject(ObjectLevelReadQuery, AbstractRecord) line: 456 ReadObjectQuery(ObjectLevelReadQuery).buildObject(AbstractRecord) line: 723 ReadObjectQuery.registerResultInUnitOfWork(Object, UnitOfWorkImpl, AbstractRecord, boolean) line: 766
ReadObjectQuery.executeObjectLevelReadQuery() line: 451
ReadObjectQuery(ObjectLevelReadQuery).executeDatabaseQuery() line: 1080 ReadObjectQuery(DatabaseQuery).execute(AbstractSession, AbstractRecord) line: 808 ReadObjectQuery(ObjectLevelReadQuery).execute(AbstractSession, AbstractRecord) line: 1040
ReadObjectQuery.execute(AbstractSession, AbstractRecord) line: 412
ReadObjectQuery(ObjectLevelReadQuery).executeInUnitOfWork(UnitOfWorkImpl, AbstractRecord) line: 1126 RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalExecuteQuery(DatabaseQuery, AbstractRecord) line: 2842 RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord, int) line: 1521 RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord) line: 1503 NoIndirectionPolicy.valueFromQuery(ReadQuery, AbstractRecord, AbstractSession) line: 323 ManyToOneMapping(ForeignReferenceMapping).valueFromRowInternal(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, AbstractSession) line: 2061 ManyToOneMapping(OneToOneMapping).valueFromRowInternal(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, AbstractSession) line: 1635 ManyToOneMapping(ForeignReferenceMapping).valueFromRow(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, CacheKey, AbstractSession, boolean) line: 1950 ManyToOneMapping(ForeignReferenceMapping).buildCloneFromRow(AbstractRecord, JoinedAttributeManager, Object, CacheKey, ObjectBuildingQuery, UnitOfWorkImpl, AbstractSession) line: 274 ObjectBuilder.buildAttributesIntoWorkingCopyClone(Object, CacheKey, ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, boolean) line: 1415 ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object) line: 1561 ObjectBuilder.buildObjectInUnitOfWork(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object, ClassDescriptor) line: 561 ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, JoinedAttributeManager) line: 497 ObjectBuilder.buildObject(ObjectLevelReadQuery, AbstractRecord) line: 456 ReadAllQuery(ObjectLevelReadQuery).buildObject(AbstractRecord) line: 723 ReadAllQuery.registerResultInUnitOfWork(Object, UnitOfWorkImpl, AbstractRecord, boolean) line: 742
ReadAllQuery.executeObjectLevelReadQuery() line: 423
ReadAllQuery(ObjectLevelReadQuery).executeDatabaseQuery() line: 1080 ReadAllQuery(DatabaseQuery).execute(AbstractSession, AbstractRecord) line: 808 ReadAllQuery(ObjectLevelReadQuery).execute(AbstractSession, AbstractRecord) line: 1040
ReadAllQuery.execute(AbstractSession, AbstractRecord) line: 383
ReadAllQuery(ObjectLevelReadQuery).executeInUnitOfWork(UnitOfWorkImpl, AbstractRecord) line: 1126 RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalExecuteQuery(DatabaseQuery, AbstractRecord) line: 2842 RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord, int) line: 1521 RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord) line: 1503 RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, List) line: 1477
EJBQueryImpl<X>.executeReadQuery() line: 484
EJBQueryImpl<X>.getSingleResult() line: 772
... (my application calls getSingleResult())


_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users





_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users





_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users





_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users


Back to the top