Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] two instances of same object in an indirectList ?


> In EclipseLink Collection will default to IndirectList when reading from the

> database if the relationship is LAZY.  If it is EAGER it will default to
> Vector.  If it were of type Set, it would default to IndirectSet or HashSet.

That makes sense, and that is what I was seeing, so that is good.


> My guess as to what you are seeing is that in the container each transaction
> is a new persistence context, so you get a new clone in each transaction
> that has the IndirectList.  Outside the container the persistence context is
> extended as long as the EntityManager exists, so when you do a find() you
> get the same object that you originally persisted, and I assume your
> constructor is setting it to a HashSet.  If you create a new EntityManager
> or refresh() the object outside the container you will get the IndirectList.

The code is a pretty simple test.  It involves two stateless session beans.  One is a "service" bean
and the other is the "persistence fascade" bean.  They both use default container managed transactions
without any explicit transaction attributes, and the fascade has its entity manager injected via a
@PersistenceContext annotation.  The fascade is then injected into the service bean with an @EJB annotation.

The purpose of the method of the particular service bean being tested is to count the number of
related Opening entities that a specific OpeningStatus or Department entity may be related to.  There are
two different methods, one for status and one for department but I'll just talk about one for the purposes
of this explanation.  The method simply takes the OpeningStatus, passes it to the fascade method which takes
the id value of the OpeningStatus, uses the entity manager in the fascade to find a managed instance of the
OpeningStatus, then return it back to the service method, and the service method calls the getOpenings
method to get the collection of related openings, then the size() method to return the size of that collection.
I know this could be done alternatively with a single jpa query but let's not get into that now.

So, in my test, the transaction should begin at the service bean method invocation and continue through
into the fascade, the instance of OpeningStatus should stay managed/attached, return the collection, and
the size should correctly be calculated since the related openings can be fetched lazily.  So the final size
is determined within a single transaction and returned back to the caller (the test code).

Also, you are correct, the constructors for OpeningStatus and Department initialize the property with a HashSet.

Is my explanation clear and my logic sound?



> As to why you have duplicates, this is odd, it means you have duplicate rows
> in your database, or you added the object to the collection twice, which is
> not good.  You should not add the object to the collection if it is already
> contained in it.

I definately do not have duplicate rows in the database... there is a primary key on the id fields of each entity
and setting FINEST log level in persistence.xml shows only a single insert, so I know the state of the database
is valid, consistent, etc.

I definately do not add the Opening to the collection properties of OpeningStatus or Department entities more
than once since I have rigid patterns for relating.  I always use the setter method on the Opening to assign an
OpeningStatus or Department to an Opening, and that setter contains the logic to managed the relationship in
both directions.  Here's example code:

public void setStatus(OpeningStatus status) {
        if (this.status != null) {
            this.status.getOpenings().remove(this);
        }
        if (status != null) {
            Collection<Opening> openings = status.getOpenings();
            if (openings != null) {
                openings.add(this);
                this.status = status;
            }
        }
    }

public void setDepartment(Department department) {
        if (this.department != null) {
            this.department.getOpenings().remove(this);
        }
        if (department != null) {
            Collection<Opening> openings = department.getOpenings();
            if (openings != null) {
                openings.add(this);
                this.department = department;
            }
        }
    }


If you can find a bug in that code which shows the entities being added twice (or any bug at all
for that matter) I'd greatly appreciate it!

I use the same pattern in about 6 or 7 other entities with one-to-many relationships and it works
fine, but I just cant find the difference for these.  I've since worked around the entire issue by explicitly
changing the types from Collection to Set, and changing all of the queries to push the returned Lists
with duplicates into Sets.  This works, but still concerned about the duplicates being returned in the
lists returned by the queries :(

Thanks!
- Phillip






> 
> 
> 
> Phillip Ross-3 wrote:
> > 
> > HI Tom, thanks for the response.  I can certainly attempt to post the
> > definition.
> > 
> > On one side of the relationship the entity has two properties as follows:
> > 
> > 
> @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})
> >  private Department department;
> > 
> > 
> @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})
> > private OpeningStatus status;
> > 
> > While on the other side, the properties are as follows:
> > 
> > @OneToMany(mappedBy = "department",
> > cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})
> > private Collectionopenings;
> > 
> > and
> > 
> > @OneToMany(mappedBy = "status",
> > cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})
> > private Collectionopenings;
> > 
> > 
> > I've worked around the issue for now by redefining all of the Collection
> > based properties as Set based instead.  Luckily they all fit within the
> > Set semantics so I'm happy to leave them that way.  But I'm still
> > wondering why the underlying Lists contain duplicates, or... are lists at
> > all rather than sets.  I should mention again that the query involves
> > invoking find() on an entity manager with either a Department or
> > OpeningStatus and both of those have Collection based relational
> > properties mapped to OpeningStatus and Department.  But the underlying
> > Collection is an IndirectList (when running inside the container) and a
> > HashSet when running outside.
> > 
> > Thanks
> > - Phillip
> > 
> > 
> > 
> > ----- Original Message ----
> >> From: Tom Ware 
> >> To: EclipseLink User Discussions 
> >> Sent: Tuesday, January 6, 2009 9:30:03 AM
> >> Subject: Re: [eclipselink-users] two instances of same object in an
> >> indirectList ?
> >> 
> >> Hi Phillip,
> >> 
> >>   I am a bit surprised that you are getting a TransparentList.  I would
> >> expect a 
> >> TransparentSet.  Can you post the definition of the relationship?
> >> 
> >> -Tom
> >> 
> >> Phillip Ross wrote:
> >> > Hi all... I'm looking for some quick ideas.
> >> > 
> >> > Was wondering if someone could quickly think of a few things for me to
> >> check 
> >> out with a problem I'm having.  I have a pair of entities with OneToMany 
> >> relationships to a third entity.  If I return an instance with the entity 
> >> manager using find and PK id, I get an instance and the Collection
> >> contains two 
> >> items.  Both items are references to the same related object... exact
> >> hashCodes, 
> >> etc.  When I run outside the container, the Collection is a HashSet and
> >> it only 
> >> contains one reference to the related item due to the Set semantics which
> >> works 
> >> great... but inside the container the Collection is an eclipselink
> >> specific 
> >> IndirectList but with dups of the same item.
> >> > 
> >> > So, might there be something I'm doing wrong that's creating the dups
> >> in the 
> >> indirect list?  I have several other similar OneToMany relations to other 
> >> entities and they don't exhibit the problem, but I've been racking my
> >> mind 
> >> trying to figure out if there is something I'm missing here to get the
> >> dedup to 
> >> happen on the IndirectList.  There are several things I'm sure I could
> >> implement 
> >> myself to work around all of this and handle deduping and such, but I'm
> >> really 
> >> wondering why this duplication happens in the indirect list with these
> >> specific 
> >> entities and not with the other three or four other similarly patterned 
> >> OneToMany related entites.
> >> > 
> >> > Any ideas?  I'm using eclipselink 1.0.2, container is glassfish
> >> v2.1-b60e 
> >> (tried with earlier glassfish versions as well).
> >> > 
> >> > Thanks!
> >> > - Phillip
> >> > 
> > 
> 
> 
> -----
> ---
> http://wiki.eclipse.org/User:James.sutherland.oracle.com James Sutherland 
> http://www.eclipse.org/eclipselink/
> EclipseLink ,  http://www.oracle.com/technology/products/ias/toplink/
> TopLink 
> Wiki:  http://wiki.eclipse.org/EclipseLink EclipseLink , 
> http://wiki.oracle.com/page/TopLink TopLink 
> Forums:  http://forums.oracle.com/forums/forum.jspa?forumID=48 TopLink , 
> http://www.nabble.com/EclipseLink-f26430.html EclipseLink 
> Book:  http://en.wikibooks.org/wiki/Java_Persistence Java Persistence 
> -- 
> View this message in context: 
> http://www.nabble.com/two-instances-of-same-object-in-an-indirectList---tp21297380p21312089.html
> Sent from the EclipseLink - Users mailing list archive at Nabble.com.
> 
> _______________________________________________
> eclipselink-users mailing list
> eclipselink-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/eclipselink-users



Back to the top