Felix
Felix

Reputation: 143

JPA/hibernate - Cannot add or update a child row: a foreign key constraint fails. Can not insert null

I'am trying to implement manyToMany relationship. It works fine when getting data from database into entities but fails when trying to insert new value into join table. I have three tables: job, job_prozedur and prozedur. Join table contains foreign keys to parent tables (job and prozedur) and few extra columns.

The entity classes are:

@Entity
@Table(name = "DOK_JOB")
Public class Job implements Serializable {

private static final long serialVersionUID = 1L;

private Integer id;
private String name;    

private List<JobProzedur> jobProzedurList = new ArrayList<JobProzedur>();

public Job() {}

@Id
@SequenceGenerator(name="seqJob", sequenceName="DOK_SEQ_1", allocationSize=1)
@GeneratedValue(generator="seqJob")
@Column(name = "JOB_ID")
public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}   

@Column(name = "JOB_NAME")
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@OneToMany(fetch = FetchType.EAGER, mappedBy = "job", cascade = CascadeType.ALL, orphanRemoval=true)
@OrderBy(value = "sortLnr")
@Cascade({org.hibernate.annotations.CascadeType.ALL})
public List<JobProzedur> getJobProzedurList() {
    return jobProzedurList;
}

public void setJobProzedurList(List<JobProzedur> jobProzedurList) {
    this.jobProzedurList = jobProzedurList;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Job other = (Job) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}
}

-

@Entity
@Table(name = "DOK_JOB_PROZEDUR")
public class JobProzedur implements Serializable {

private static final long serialVersionUID = 7971463524201735449L;

private JobProzedurId id = new JobProzedurId();
private Integer sortLnr;

private Job job;
private Prozedur proz;

public JobProzedur() {}

@EmbeddedId
public JobProzedurId getId() {
    return id;
}

public void setId(JobProzedurId id) {
    this.id = id;
}

@Column(name = "SORT_LNR")
public Integer getSortLnr() {
    return sortLnr;
}

public void setSortLnr(Integer sortLnr) {
    this.sortLnr = sortLnr;
}   

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "JOB_ID", referencedColumnName = "JOB_ID", insertable=false, updatable=false, nullable=false)
public Job getJob() {
    return job;
}

public void setJob(Job job) {
    this.job = job;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "PROZ_ID", referencedColumnName = "PROZ_ID", insertable=false, updatable=false)
public Prozedur getProz() {
    return proz;
}

public void setProz(Prozedur proz) {
    this.proz = proz;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    JobProzedur other = (JobProzedur) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}   

}

-

@Embeddable
public class JobProzedurId implements Serializable {

private static final long serialVersionUID = 1L;    

private Integer jobId;
private Integer prozId; 

public JobProzedurId() {}   

public JobProzedurId(Integer jobId, Integer prozId) {
    super();
    this.jobId = jobId;
    this.prozId = prozId;
}

@Column(name = "JOB_ID", nullable=false)
public Integer getJobId() {
    return jobId;
}

public void setJobId(Integer jobId) {
    this.jobId = jobId;
}

@Column(name = "PROZ_ID")
public Integer getProzId() {
    return prozId;
}

public void setProzId(Integer prozId) {
    this.prozId = prozId;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((jobId == null) ? 0 : jobId.hashCode());
    result = prime * result + ((prozId == null) ? 0 : prozId.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    JobProzedurId other = (JobProzedurId) obj;
    if (jobId == null) {
        if (other.jobId != null)
            return false;
    } else if (!jobId.equals(other.jobId))
        return false;
    if (prozId == null) {
        if (other.prozId != null)
            return false;
    } else if (!prozId.equals(other.prozId))
        return false;
    return true;
}

@Override
public String toString() {
    return "JobProzedurId [jobId=" + jobId + ", prozId=" + prozId + "]";
}

}

-

@Entity
@Table(name = "DOK_PROZEDUR")
public class Prozedur implements Serializable {

private static final long serialVersionUID = 1L;

private Integer id;
private String dbName;
private String schemaName;
private String packageName;
private String name;

public Prozedur() {}

@Id
@SequenceGenerator(name="seqProz", sequenceName="DOK_SEQ_1", allocationSize=1)
@GeneratedValue(generator="seqProz")
@Column(name = "PROZ_ID")
public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

@Column(name = "DB_NAME")
public String getDbName() {
    return dbName;
}

public void setDbName(String dbName) {
    this.dbName = dbName;
}

@Column(name = "SCHEMA_NAME")
public String getSchemaName() {
    return schemaName;
}

public void setSchemaName(String schemaName) {
    this.schemaName = schemaName;
}

@Column(name = "PACKAGE_NAME")
public String getPackageName() {
    return packageName;
}

public void setPackageName(String packageName) {
    this.packageName = packageName;
}

@Column(name = "PROZ_NAME")
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Prozedur other = (Prozedur) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}

}

The part of code where I assign prozedur to job and persist is:

//      ...
//      ...
    JobProzedur jobProz = new JobProzedur();
    jobProz.setJob(job);
    jobProz.setProz(proz);

    job.getJobProzedurList().add(jobProz);

    entityManager.persist(job);
    entityManager.flush();

When persisting I get exception:

org.hibernate.exception.ConstraintViolationException: ORA-01400: cannot insert NULL into ("DOK"."DOK_JOB_PROZEDUR"."JOB_ID")

I don't know why hibernate doesn't assign values to foreign keys columns in join table during persist. Update works because I assign those values manually, but that is not the right way. Any help is appreciated. I've been working on this for few days now and I see no solution. Please help!

Upvotes: 1

Views: 6922

Answers (1)

JB Nizet
JB Nizet

Reputation: 692231

You forgot to add an @MapsId annotation on JobProzedur.getProz() and JobProzedut.getJob()

EDIT: And as @PepperBob says: the associations shouldn't be marked as insertable=false and updatable=false, since you precisely want to insert them.

But I would make my life much easier, and the application faster, by using a single-column, auto-generated primary key instead of a composite primary key. Use a unique constraint to guarantee that two rows with the same job ID and the same prozedur ID can't exist.

Upvotes: 1

Related Questions