This discussion is archived
5 Replies Latest reply: Aug 31, 2012 6:59 AM by cdelahun RSS

Need advice regarding the use of Private Owned

618233 Newbie
Currently Being Moderated
Hello,

We have the following JPA entity objects:

@Entity
public class Claim {
@PrivateOwned
@OneToMany(mappedBy = "claim", cascade = CascadeType.ALL)
private List<ClaimLine> claimLineList;
}

@Entity
public class Bill {
@OneToMany(mappedBy = "bill", cascade = CascadeType.ALL)
private List<ClaimLine> claimLineList;
}

@Entity
public class ClaimLine {
@ManyToOne
@JoinColumn(name = "CLAI_ID", nullable = false)
private Claim claim;

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "BILL_ID")
private Bill bill;
}

Both Claim and Bill have many-to-one references to ClaimLine. The ClaimLine is Privately Owned by the Claim.
Note that when a Claim is removed, the entire object graph is discarded, i.e. the Bill and ClaimLine objects are also removed. The Bill can be removed without removing the ClaimLine objects.

The EclipseLink documentation [ http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#How_to_Use_the_.40PrivateOwned_Annotation ] specifies that:
"+An object should not be the target in more than one relationship if it is the target in a privately owned relationship.+"

Question: are we running a risk having the ClaimLine object as target in more than one relationship?

Thanks.

Best regards,
-Sjoerd
  • 1. Re: Need advice regarding the use of Private Owned
    cdelahun Pro
    Currently Being Moderated
    Hello,

    When you remove a Claim entity, you will need to clean up all references other entities might have back to the claim item. Because Claim has a privately owned relationship to ClaimLine, all references to the ClaimLines that are to be deleted also need to be cleaned up, or Bill will be inadvertently left referencing a deleted ClaimLine in the cache. If Bill is removed, references to it must be nulled out - specifically in the ClaimLine, but you have to do this in the application or get a constraint violation on the database anyway.

    The risk with privately owned objects is that they are deleted outside the normal constraint checking rules. That is, if ClaimLine is not marked for deletion but its owning Claim is, ClaimLine will not get deleted until the delete for Claim is processed. That means depending on delete ordering, if Bill is marked for delete, it could get processed first, and so deleted deleted before the Claim + ClaimLine, causing a dependency violation. As long as you are setting the ClaimLine->Bill relation to null you won't get a problem. If you are not, and bills are getting deleted first, you can order the dependencies manually so that Claim is always processed for deletes first using addConstraintDependencies on the Claim descriptor described at: http://wiki.eclipse.org/Using_Advanced_Unit_of_Work_API_%28ELUG%29#How_to_Use_the_addConstraintDependencies_Method_of_the_Descriptor

    Best Regards,
    Chris
  • 2. Re: Need advice regarding the use of orphanRemoval=true
    153666 Newbie
    Currently Being Moderated
    We now use EclipseLink 2.3.2, and have replaced our @PrivateOwned annotations with an addition of orphanRemoval=true on the @OneToMany annotation.
    In the meantime, the EclipseLink documentation that used to be at [ http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#How_to_Use_the_.40PrivateOwned_Annotation ] has moved to [ http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_privateowned.htm ] and now explicitly makes an exception for "intersection" entities:

    Normally, do not configure privately owned relationships on objects that might be shared. An object should not be the target in more than one relationship if it is the target in a privately owned relationship.

    The exception to this rule is the case when you have a many-to-many relationship in which a relation object is mapped to a relation table and is referenced through a one-to-many relationship by both the source and the target. In this case, if the one-to-many mapping is configured as privately owned, then when you delete the source, all the association objects will be deleted.

    Does this mean that in our example of Claim, Bill and ClaimLine we can now have orphanRemoval=true both on the OneToMany from Claim to ClaimLine and on the OneToMany from Bill to ClaimLine, without having the problems described earlier in this thread?
  • 3. Re: Need advice regarding the use of orphanRemoval=true
    cdelahun Pro
    Currently Being Moderated
    Orphanremoval is just private ownership with an automatic cascade.remove set, so the same issues apply. You must manage any relionships to entities that are to be removed regardless of how they are to be removed. Delete ordering might not be as much of a problem though since if you delete a Claim, since the delete cascades to the claimItem and then to Bill, and the claimItem should be deleted before either the bill or claim are - EclipseLink will be aware of the constraint dependencies.

    If you delete a Bill though, you might get problems since the delete is not cascaded to Claims - a claim may be left referencing deleted claimLines, causing them to be resurected with incorrect references.

    Best Regards,
    Chris

    Edited by: cdelahun on Aug 30, 2012 12:06 PM
  • 4. Re: Need advice regarding the use of orphanRemoval=true
    153666 Newbie
    Currently Being Moderated
    Thank you Chris, that helps with understanding the issue.

    If this is the underlying problem, can you explain to me why does the EclipseLink documentation make an exception for a many-to-many relationship in which a relation object is mapped to a relation table and is referenced through a one-to-many relationship by both the source and the target?

    For example, if you have entities User and Role, and a many-to-many relationship between User and Role, you would have the following:

    @Entity
    public class User{
    @PrivateOwned
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<UserRole> userRoleList;
    }

    @Entity
    public class Role {
    @OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
    private List<UserRole> userRoleList;
    }

    @Entity
    public class Role {
    @ManyToOne
    @JoinColumn(name = "USER_ID", nullable = false)
    private User user;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "ROLE_ID")
    private Role role;
    }

    Wouldn't you get the same problems if a User is deleted, it cascade-deletes to its UserRoles, and then the Role might be left referencing deleted userRoles?

    kind regards,
    Sandra
  • 5. Re: Need advice regarding the use of orphanRemoval=true
    cdelahun Pro
    Currently Being Moderated
    I am trying to find out where the exception in the documentation came from or what it should mean. It is somewhat correct - the privately owned objects will be deleted and there shouldn't be a constraint violation in the database. It doesn't mean you don't have to be careful though about what is referencing those privately owned objects and how. While the privetely owned object will be deleted correctly, any objects that still reference it in the cache will continue to reference it once it is deleted - those references need to be cleaned up somehow or the cache is inconsistent.

    In your User/Role example, the privately owned relationship shouldn't cause problems that I'm aware of. When you remove a User, it should correctly cascade over the UserRole and Role objects. You will likely get seemingly very strange and inconsistent behavior when deleting a Role though- this will cause UserRoles to be removed because of the Cascade.ALL setting, but doesn't cascade to User. So if a User exists in the cache, it will potentially still have references to those UserRoles that are being removed - This mapping is marked as cascade persist, so they should get inserted if/when they are found.

    Best Regards,
    Chris

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points