简体   繁体   中英

Mapping a bidirectional One-to-Many Hibernate Entity

I am trying to map a bi-directional (one to many and many to one) relationship in Hibernate. We're getting errors when attempting save a result.

The error we're getting is:

Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value : com.example.Component.resultId at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:92)

From the source code below a Result can have many Component s and many Component s can belong to a single Result . One of the requirement is that the resultId in Result must be a String . This requirement is out of our control.

An example Entity source code is below:

@Entity
@Table(name = "result")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Result extends AbstractEntity {

    @OneToMany(cascade = CascadeType.MERGE)
    @JoinColumn(name = "resultId")
    private List<Component> component = new ArrayList<>();
}

@Entity
@Table(name = "cmpt")
@XmlRootElement
public class Component extends AbstractEntity {
    @ManyToOne(targetEntity = Result.class)
    private String resultId;
}

Here is the solution that worked for me

@Entity
@Table(name = "result")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Result extends AbstractEntity {

    @OneToMany(cascade = CascadeType.MERGE, nullable = false)
    @JoinColumn(name = "resultId")
    private List<Component> component = new ArrayList<>();
}

@Entity
@Table(name = "cmpt")
@XmlRootElement
public class Component extends AbstractEntity {
    @Column(name = "result_id", insertable = false, updatable = false, nullable = false)
    private String resultId;
}

The correct way to create a bidirectional entity is this.

@Entity
@Table(name = "result")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Result extends AbstractEntity {

    @OneToMany(cascade = CascadeType.MERGE, mappedBy="result")
    private List<Component> component = new ArrayList<>();
}

@Entity
@Table(name = "cmpt")
@XmlRootElement
public class Component extends AbstractEntity {
    @ManyToOne(targetEntity = Result.class)
    @JoinColumn(name = "result_id")  //result_id is the column name (foreign key) in cmpt table
    private Result result;

    @Column(name = "result_id", insertable = false, updatable = false)
    private String resultId;
}

This will ensure there will be only one bi-direction relation (not two uni-directional relations etc). Let me know if you are expecting something else.

Update 1:

You can add another key to the entity as specified above. You'll get the foreign key as a string. But you need to remember that the actual mapping with JoinColumn should not be removed. I have tested the above configuration and it seems to work for me.

You have to declare an entity as the field annotated with @ManyToOne. Also i think in your case you should put the @Join column on the Component side:

@Entity
@Table(name = "cmpt")
@XmlRootElement
public class Component extends AbstractEntity {
    @ManyToOne
    @JoinColumn(name = "resultId")
    private Result result;
}

now you dont need the targetEntity attrbute.

Also remove the @JoinColumn from @OneToMany and add mappedBy attribute:

@Entity
@Table(name = "result")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Result extends AbstractEntity {

    @OneToMany(cascade = CascadeType.MERGE, mappedBy="result")
    private List<Component> component = new ArrayList<>();
}

我认为您必须从Component.java类中删除@ManyToOne(targetEntity = Result.class)批注,并且当您尝试保存数据时,首先必须使用save方法保存Result ,然后通过save方法将返回的resultId设置为此使用setter和getter在组件实体中的resultId ,然后保存组件

Here is the solution that worked for me:

@Entity
@Table(name = "result")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Result extends AbstractEntity {

    @OneToMany(cascade = CascadeType.MERGE, nullable = false)
    @JoinColumn(name = "resultId")
    private List<Component> component = new ArrayList<>();
}

@Entity
@Table(name = "cmpt")
@XmlRootElement
public class Component extends AbstractEntity {
    @Column(name = "result_id", insertable = false, updatable = false, nullable = false)
    private String resultId;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM