-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Constraint Problems with Collections in Hibernate
PostPosted: Mon Nov 15, 2010 12:59 pm 
Newbie

Joined: Fri Nov 12, 2010 10:07 am
Posts: 2
I have been trying to debug constraint problems with collections in Hibernate.

The problem happens when you try to add an additional child to an already existing parent. For example:

1. Run a batch job that creates a person with one role.

2. Run a second batch job that adds a second role to the same person.

When Hibernate persists I get this error, even though I can verify that the sponsorid has been set before calling:
entityManager.merge(person);

<ORA-01400: cannot insert NULL into ("PRS_ROLE_RECORDS"."SPONSOR_ID")>

There is a not null constraint on sponsor_id.

I added triggers to the tables that were having constraint problems so that any insert/update/delete could be logged to another table.

When I disabled the not null constraint on sponsor id (and sponsor_t) then the role was successfully added. When I looked at my log, I found the following:

prs_role_records INSERT Record_ID: 48243 Percent Time: 100 RoleId: 1257 Sponsorid: Sponsor Type: Id: 96303 source_sor_id: SRDB affiliation_date: 01-MAY-95 sor_person_id: 33196

prs_role_records UPDATE Record_ID: 48243 Percent Time: 100 RoleId: 1257 Sponsorid: 213 Sponsor Type: 29 Id: 96303 source_sor_id: SRDB affiliation_date: 01-MAY-95 sor_person_id: 33196


What you see is that Hibernate did a two step save. An initial insert with sponsorid null (and sponsor_t) . Followed by an update with sponsorid (and sponsor_t) filled in.

I do not see any reason for this given that the sponsorid (and sponsor_t) was already set before calling merge. I also don't see why it singled out sponsorid (and sponsor_t) when other values seem to be filled in on the insert statement. Could anybody help explain why the merge was done in a two step process and why it did not have the value of sponsor id (and sponsor_t) at the time of the insert?

Thanks for your help!

The code:

Person table:
Code:
@Table(name = "prs_sor_persons")
@org.hibernate.annotations.Table(appliesTo = "prs_sor_persons", indexes = {@Index(name = "SOR_PERSON_SOURCE_AND_ID_INDEX", columnNames = {"source_sor_id", "id"})})
public class JpaSorPersonImpl extends Entity implements SorPerson {

    @Id
    @Column(name = "record_id")
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "prs_sor_persons_seq")
    @SequenceGenerator(name = "prs_sor_persons_seq", sequenceName = "prs_sor_persons_seq", initialValue = 1, allocationSize = 50)
    private Long recordId;

    @Column(name = "id")
    @Required(property = "person.sorId")
    private String sorId;

    @Column(name = "source_sor_id", nullable = false)
    @NotNull
    @Size(min = 1)
    private String sourceSor;

    @Column(name = "person_id")
    private Long personId;

    @Column(name = "date_of_birth", nullable = true)
    @Temporal(TemporalType.DATE)
    @Required(property = "person.dateOfBirth", message = "dateOfBirthRequiredMsg")
    @Past
    private Date dateOfBirth;

    @Column(name = "gender", length = 1, nullable = true)
    @Required(property = "person.gender", message = "{genderRequiredMsg}")
    @Size(min = 1, max = 1, message = "genderRequiredMsg")
    @Gender
    private String gender;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "person", fetch = FetchType.EAGER, targetEntity = JpaSorNameImpl.class)
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @Fetch(value = FetchMode.SUBSELECT)
    @RequiredSize(property = "person.names")
    @Valid
    private List<SorName> names = new ArrayList<SorName>();

    @Column(name = "ssn", nullable = true, length = 9)
    @Required(property = "person.ssn")
    private String ssn;

    @OneToOne(cascade=CascadeType.ALL, mappedBy="person", fetch = FetchType.EAGER, targetEntity = JpaSorDisclosureSettingsImpl.class)
    private JpaSorDisclosureSettingsImpl disclosureSettings;

[b]    @OneToMany(cascade = CascadeType.ALL, mappedBy = "person", fetch = FetchType.EAGER, targetEntity = JpaSorRoleImpl.class)
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @Fetch(value = FetchMode.SUBSELECT)
    @Valid
    private List<SorRole> roles = new ArrayList<SorRole>();[/b]


Role Table:
Code:
@javax.persistence.Entity(name = "sorRole")
@Table(name = "prs_role_records", uniqueConstraints = @UniqueConstraint(columnNames = {"source_sor_id", "id"}))
@org.hibernate.annotations.Table(appliesTo = "prs_role_records", indexes = @Index(name = "PRS_ROLE_SOR_PERSON_INDEX", columnNames = "sor_person_id"))
public class JpaSorRoleImpl extends Entity implements SorRole {

    @Id
    @Column(name = "record_id")
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "prs_role_records_seq")
    @SequenceGenerator(name = "prs_role_records_seq", sequenceName = "prs_role_records_seq", initialValue = 1, allocationSize = 50)
    private Long recordId;

    @Column(name = "id")
    @NotNull
    @Size(min = 1)
    private String sorId;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "sorRole", fetch = FetchType.EAGER, targetEntity = JpaSorUrlImpl.class)
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @RequiredSize(property = "role.urls")
    @Valid
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Url> urls = new ArrayList<Url>();

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "sorRole", fetch = FetchType.EAGER, targetEntity = JpaSorEmailAddressImpl.class)
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @RequiredSize(property = "role.emailAddresses")
    @Valid
    @Fetch(value = FetchMode.SUBSELECT)
    private List<EmailAddress> emailAddresses = new ArrayList<EmailAddress>();

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "sorRole", fetch = FetchType.EAGER, targetEntity = JpaSorPhoneImpl.class)
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @RequiredSize(property = "role.phones")
    @Valid
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Phone> phones = new ArrayList<Phone>();

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "sorRole", fetch = FetchType.EAGER, targetEntity = JpaSorAddressImpl.class)
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @RequiredSize(property = "role.addresses")
    @Valid
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Address> addresses = new ArrayList<Address>();

    @Column(name = "source_sor_id", nullable = false)
    @NotNull
    @Size(min = 1)
    private String sourceSorIdentifier;

    @ManyToOne(optional = false)
    @JoinColumn(name = "sor_person_id", nullable = false)
    private JpaSorPersonImpl person;

    @Column(name = "percent_time", nullable = false)
    @DecimalMin(value = "0")
    @DecimalMax(value = "100")
    private int percentage;

    @ManyToOne(optional = false)
    @JoinColumn(name = "person_status_t")
    @NotNull
    @AllowedTypes(property = "role.personStatus")
    private JpaTypeImpl personStatus;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "sorRole", fetch = FetchType.EAGER, targetEntity = JpaSorLeaveImpl.class)
    @RequiredSize(property = "role.leaves")
    @Valid
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Leave> leaves = new ArrayList<Leave>();

    @ManyToOne(optional = false)
    @JoinColumn(name = "role_id")
    @NotNull
    private JpaRoleInfoImpl roleInfo;

[b]    @Column(name="sponsor_id", nullable = false)
    @NotNull
    private Long sponsorId;

    @ManyToOne(optional = false)
    @JoinColumn(name="sponsor_t")
    @NotNull
    private JpaTypeImpl sponsorType;[/b]

    @Column(name = "affiliation_date", nullable = false)
    @Temporal(TemporalType.DATE)
    @NotNull(message = "startDateRequiredMsg")
    private Date start;

    @Column(name = "termination_date")
    @Temporal(TemporalType.DATE)
    private Date end;

    @ManyToOne()
    @JoinColumn(name = "termination_t")
    private JpaTypeImpl terminationReason;


Top
 Profile  
 
 Post subject: Re: Constraint Problems with Collections in Hibernate
PostPosted: Fri Nov 19, 2010 10:05 am 
Newbie

Joined: Fri Nov 12, 2010 10:07 am
Posts: 2
I figured out the problem.

In our code we were creating the child object, adding it to the parent and then setting the values of the object. When I changed the code to call the child setters first and then added the child to the parent, one insert was done instead of an insert followed by an update.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.