通过@JoinTable在JPA / Hibernate @OneToMany列表(使用@OrderColumn)映射中遇到困难

时间:2018-05-03 19:22:11

标签: hibernate jpa

我是JPA&我正在学习“Java Persistence With Hibernate 2nd Edition”一书。 @JoinTable在@OneToMany双向List(带@OrderColumn)映射方面遇到了一些困难。我没有遇到@JoinColumn的任何问题,但似乎我在@JoinTable的情况下做错了。我在下面给出了我的例子。

ADDRESS CLASS:

@Entity
@Table(name = "ADDRESS")
public class Address {
    @Id
    @GeneratedValue(generator = "MY_ID_GENERATOR")
    @Column(name="_ADDRESS_ID")
    private Long addressId;

    @NotNull
    @Column(name="_CITY", nullable = false)
    protected String city;

    //-------------------------------------
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinTable(
        name = "ADDRESS_LIST",
        joinColumns = {@JoinColumn(name = "_A_ID", unique = true, updatable = false, insertable = false, referencedColumnName = "_ADDRESS_ID")},
        inverseJoinColumns = {@JoinColumn(name = "_P_ID", updatable = false, insertable = false, referencedColumnName = "_PERSON_ID")}
    )
    private Person person;
    //-------------------------------------

    protected Address() {}
    public Address(@NotNull String city) {
        super();
        this.city = city;
    }
    public Address(@NotNull String city, Person person) {
        super();
        this.city = city;
        this.person = person;
    }
    public Long getId() { return addressId; }
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    public Person getPerson() { return person; }
    public void setPerson(Person person) { this.person = person; }
}

PERSON CLASS:

@Entity
@Table(name = "PERSON")
public class Person {
    @Id
    @GeneratedValue(generator = "MY_ID_GENERATOR")
    @Column(name="_PERSON_ID")
    private Long personId;

    @NotNull
    @Column(name="_NAME", nullable = false, length = 50)
    private String name;

    //-------------------------------------
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, orphanRemoval = true)
    @JoinTable(
        name = "ADDRESS_LIST",
        joinColumns = {@JoinColumn(name = "_P_ID", referencedColumnName = "_PERSON_ID")},
        inverseJoinColumns = {@JoinColumn(name = "_A_ID", unique = true, referencedColumnName = "_ADDRESS_ID")}
    )
    @OrderColumn(name = "_ORDER", nullable = false)
    private List<Address> addressList = new ArrayList<>();
    //-------------------------------------

    public Person() {
        super();
    }
    public Person(@NotNull String name) {
        super();
        this.name = name;
    }
    public Long getPersonId() { return personId; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public List<Address> getAddressList() { return addressList; }
    public void setAddressList(List<Address> addressList) { this.addressList = addressList; }
}

现在在主要课程中,如果我照顾双方协会,那就不起作用!!

Person person = new Person("Sourangshu Biswas");
person.getAddressList().add(new Address("Siliguri", person));
person.getAddressList().add(new Address("Kolkata", person));
person.getAddressList().add(new Address("Chennai", person));

给出错误!!

Caused by: java.sql.SQLException: Field '_P_ID' doesn't have a default value.

但如果我没有在“地址()”缩写器中传递“person”对象,它就可以了。

Person person = new Person("Sourangshu Biswas");
person.getAddressList().add(new Address("Siliguri"));
person.getAddressList().add(new Address("Kolkata"));
person.getAddressList().add(new Address("Chennai"));

我已经检查了数据库,我在“_ORDER”列中也获得了值!但问题是这是如何工作的!据我所知,我们必须在双向关联中照顾双方。当我在“地址()”缩写器中传递“人物”对象时为什么它不起作用!!!! ?? “人”对象尚未持久,这是为什么?但是我在映射的其他类型(SET / BAG)中完成了同样的事情,那时它起作用了。

1 个答案:

答案 0 :(得分:0)

  

注意:它是双向LIST映射,我也想使用OrderColumn。根据&#34; Java Persistence With Hibernate第2版&#34;本书(第185页),这个例子是一个例外。

本书提到的是使用连接列创建有序双向一对多关联的解决方法,这是非常不同的。实际上,您在这里创建了两个碰巧使用相同连接表的单独关联。现在:

  

如果我没有通过&#34;那个人&#34; &#34;地址()&#34;中的对象缩窄,它正在发挥作用。

Address.person设置为null时,Hibernate不会尝试保持多对一关联。因此,生成单个INSERT语句(仅存储一对多关联):

INSERT INTO ADDRESS_LIST(_P_ID, _A_ID) VALUES (?, ?);
  在主要课程中,如果我照顾双方协会,它就不起作用!!

如果您将Address添加到Person.addressList 将非空Person分配给Address.person,Hibernate会尝试将两个关联都保留。将生成两个INSERT语句:一个用于一对多关联(类似于上面的一个),另一个用于多对一关联 - 如下所示:

INSERT INTO ADDRESS_LIST() VALUES ();

为什么空列列表和空值列表? 因为您已标记了联接表insertable=false 的两个加入列。数据库抱怨缺少_P_ID列的值 - 这是可以理解的,因为_P_ID不能是NULL,并且没有默认值可供使用。

当然,如果删除insertable=false,则两个INSERT语句将完全相同,从而导致约束违规或ADDRESS_LIST中的重复行。

长话短说:你不应该照顾协会的双方,因为这不是双向关联 - 这实际上是两个完全独立的关联。

请注意,对于类似于加入列方法的解决方法,您需要将整个多对一@JoinTable标记为insertable=false,而不仅仅是单个连接列 - JPA不支持的内容。