Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] EntityManager.remove does not remove entity from cache

I think this whole issue boils down to the following statement in the spec:
"It is the developer’s responsibility to keep the in-memory references
held on the owning side and those held on the inverse side consistent with each other when they change."

This, then, relies on the definition of "in-memory". It seems that eclipselink has included the cache in the scope of "in-memory". I believe the intent of the statement is that the object maintained by the app will not be modified by JPA, but not that a future query (or find) will reflect the change. Consider an embedded in-memory database. If this statement was interpreted in a strict manner, it would conflict with the statement that the entity must be removed from the database.

Aside from the above, the differential between the cache and database certainly leads to counter-intuitive situations that I have previously described.

mike

christopher delahunt wrote:
Hello Samba,

1) yes, and it currently does. 2) Maybe. It depends on if A's collection of children was fetched previously or not. If it was not fetched yet (if its lazy), when it is fetched it goes to the database, otherwise, it is as it is in the cache 3) The developer should maintain all relationships because JPA allows providers to use a cache. There is no way to know that an object's lazy relationships have been prefetched or not, and if they have, then they have to be maintained 4) Yes. When you remove an entity, an application should remove all references to it from other entities. 5) I'm not sure how this could be automatically handled, but is a valid feature request. The provider cannot know if A is around in the cache or not, or even if A is the only object referencing B. Such a feature might be nice, but I dont know how it would affect performance positively. 6) As references to removed entities are supposed to be cleared up, extra existence checking on each relationship might impact performance significantly enough to reduce the value of a cache at all. It might be seen as excessive to avoid a problem that is already considered to be an application issue. The other issue that would then arise is what to do when a removed reference is discovered, and how to even tell that this non-existing object was a removed object and not something added by the user (EclipseLink allows read-only access to its shared cache). 7) I don't know what A.getChildren().get(0).getB() is meant to return, I assume get(0) would return a B object? EclipseLink returns the A object from the cache, so the collection of children would be as they were originally constructed. The problem is not that B is still cached after it is removed, but that other entities that are cached still reference the removed B. When these are brought into the context, B is in essence resurected, and I believe this problem in mind when the JPA spec stated "Note that it is the application that bears responsibility for maintaining the consistency of runtime relationships", but thats my opinion of course.

Best Regards,
Chris


Samba wrote:
Excuse me Tom for intervening in the discussion, but I suppose what Mike says is quite correct! 1. when em.remove(object-of-B); is called, shouldn't it remove that entity instance from the cache as well? 2. when A is fetched from a new transaction, shouldn't the object-of-A.getChildren() be a fresh list of objects of B? 3. So, where does the "developer maintaining the relationship" come into picture? 4. do you mean the developer should also remove the association between A and B? 5. I believe this should have been handled automatically with @ManyToOne annotation on the child side of the relation ship 6. It would be better if eclipselink checks for existence of the enitiy before loading the relationship in case if the relation has not been cleaned up. 7. Further, it would interesting to see if the A.getChildren().get(0).getB() is returning the complete details of the object or just the priomary key of the object. I suspect, it is only retuning the primary key and hence a bug in the way eclipselink is constructing objects from references. Regards,
Samba
On Tue, Sep 1, 2009 at 8:49 PM, Tom Ware <tom.ware@xxxxxxxxxx <mailto:tom.ware@xxxxxxxxxx>> wrote:

    There may be an enhancement request in there somewhere.  Please
    feel free to enter one.

    At the moment the JPA specification requires that you maintain
    your relationships and does not mandate any automatic relationship
    maintenance by the provider.

    -Tom


    Mike Traum wrote:

        Sure. Here's a snippet:

          EntityManager em = emf.createEntityManager();
          Query q = em.createQuery("select a FROM A a");
          List<A> as = q.getResultList();
          em.clear();
          em.close();
            B b = as.get(0).getChildren().get(0);
          System.out.println(b.getId()); // prints '2'
            em = emf.createEntityManager();
          em.getTransaction().begin();
          B bm = em.merge(b);
          em.remove(bm);
          em.getTransaction().commit(); // successfully removes b with
        id '2' from database
          em.clear();
          em.close();
            em = emf.createEntityManager();
          q = em.createQuery("select a FROM A a");
          as = q.getResultList();
          b = as.get(0).getChildren().get(0);
          System.out.println(b.getId()); // prints '2'
          boolean contains = em.contains(b);
          System.out.println(contains); // prints 'true'
          em.clear();
          em.close();


        mike

        Tom Ware wrote:

            I am not sure I follow.   Can you provide a code sample?

            Mike Traum wrote:

                Tom,
                I see where you're coming from. The spec references
                that you gave do seem to support this behavior
                (unfortunate, but that's an issue for a different
                list). But, I think you then run into other conflicts
                with the spec. For example, contains on that the
                removed entity will return true after retrieving it
                with the query.

                Section 3.2.5
                The contains method returns true:
                • If the entity has been retrieved from the database,
                and has not been removed or detached.
                • If the entity instance is new, and the persist
                method has been called on the entity or the persist
                operation has been cascaded to it.

                The contains method returns false:
                • If the instance is detached.
                • If the remove method has been called on the entity,
                or the remove operation has been cascaded
                to it.
                • If the instance is new, and the persist method


                mike


                mike

                Tom Ware wrote:

                    The spec references I have found are in section
                    3.2.3 of the JPA 1.0 specification:

                    Reference 1:
                    ---
                    Bidirectional relationships between managed
                    entities will be persisted based on references
                    held by the
                    owning side of the relationship. It is the
                    developer’s responsibility to keep the in-memory
                    references
                    held on the owning side and those held on the
                    inverse side consistent with each other when they
                    change.
                    ---

                    Reference 2: (for flushing)

                    ----
                    The semantics of the flush operation, applied to
                    an entity X are as follows:

                    <snip>
                    - If X is a removed entity, it is removed from the
                    database. No cascade options are relevant.
                    ----

                    Is there something I am missing in the spec that
                    you can point me to?

                    -Tom


                    Mike Traum wrote:

                        Maybe I've been defining my entities
                        strangely, but if you define a @OneToMany on A
                        and then a @ManyToOne on B (pointing to A),
                        the schema generated by eclipselink will have
                        the foreign key in B pointing to A. So, this
                        will not be enforced by the database. I can
                        drop in some code to illustrate if desired.

                        If the above is not funky, I think, by the JPA
                        spec, the DB delete should not occur.
                        Otherwise, the relationship 'magic' will occur
                        between app restarts but not within app queries.

                        mike

                        Tom Ware wrote:

                            EclipseLink relies on your DB
                            foreign-key-contstraints to enforce this.

                            i.e. You should get a SQL exception on the
                            remove if a foreign-key-constraint exists
                            for this relationship.

                            Mike Traum wrote:

                                Yes, I thought that might be the
                                answer. But, the implementation seems
                                odd. JPA doesn't provide magic for
                                this, but it is deleted from the
                                database, however the cache is
                                maintained in a stale state. It seems
                                to me that either it should not be
                                deleted from the database or it should
                                be removed from the cache.

                                mike

                                Tom Ware wrote:

                                    Hi Mike,

                                     You need to sever the
                                    relationship between an A and a B
                                    before you remove B.  JPA does not
                                    provide any magic for this.

                                    -Tom

                                    Mike Traum wrote:

                                        I have the following enitiy map:
                                        A->B->C (where -> represents a
                                        OneToMany relationship)

                                        If I do a EntityManager.remove
                                        on a B, a following Query
                                        (select all) will still return
                                        that entity, even though it
                                        has been removed from the
                                        database.

                                        Any ideas on the proper way to
                                        handle this?

                                        Here's some code illustrating
                                        the issue:
                                          EntityManager em =
                                        emf.createEntityManager();
                                          Query q =
                                        em.createQuery("select a FROM
                                        A a");
List<A> as = q.getResultList();
                                          em.clear();
                                          em.close();
System.out.println(as.get(0).getChildren().size());
                                        // output is 2
                                            B b =
                                        as.get(0).getChildren().get(0);
                                            em =
                                        emf.createEntityManager();
                                          em.getTransaction().begin();
                                          B bm = em.merge(b);
                                          em.remove(bm);
em.getTransaction().commit();
                                        // successfully removes B and
                                        children from database
                                          em.clear();
                                          em.close();

em = emf.createEntityManager();
                                          q = em.createQuery("select a
                                        FROM A a");
                                          as = q.getResultList();
                                          em.clear();
                                          em.close();
System.out.println(as.get(0).getChildren().size());
                                        // output is 2
                                            em =
                                        emf.createEntityManager();
                                          q = em.createQuery("select a
                                        FROM A a");
((ReadAllQuery)((EJBQueryImpl)q).getDatabaseQuery()).refreshIdentityMapResult();

                                          as = q.getResultList();
                                          em.clear();
                                          em.close();
System.out.println(as.get(0).getChildren().size());
                                        // output is 1


                                        Thanks,
                                        Mike

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

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

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

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

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

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

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

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

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

    _______________________________________________
    eclipselink-users mailing list
    eclipselink-users@xxxxxxxxxxx <mailto: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