如何避免在一对多单向关联中插入和更新查询

Posted

技术标签:

【中文标题】如何避免在一对多单向关联中插入和更新查询【英文标题】:How to avoid insert and update queries in one-to-many uni-directional association 【发布时间】:2016-02-14 07:23:01 【问题描述】:

我在EmployeePhone 实体之间有一个简单的one-to-many 关系。

我这里有 2 个问题。

场景 1:

@Entity
public class Employee 
    @Id
    @GeneratedValue
    private long id;

    private String firstName;
    private String lastName;
    private double salary;

    @OneToMany
    @JoinColumn(name = "parent_id", referencedColumnName = "id", insertable=false, updatable=false)
    private List<Phone> phones = new ArrayList<Phone>(0);

// Setters & Getter methods


Phone.java

@Entity
public class Phone 
    @Id
    private long id;
    private String type;
    private int areaCode;
    private String phoneNumber;

// Setter & Getters


现在我创建了员工实例并向其中添加了 2 部电话。

Employee e1 = new Employee(10,"Bob", "Way",50000);
Phone p1 = new Phone(1,"home",613,"792-0000");
Phone p2 = new Phone(2,"work",613,"896-1234");          
e1.addPhone(p1);
e1.addPhone(p2);

然后在休眠中,如果我使用下面的代码:

session.save(e1);
session.save(p1);
session.save(p2);

或者如果我保存phone 然后employee

session.save(p1);
session.save(p2);
session.save(e1);

在这两种情况下,Hibernate 只运行 insert 查询而没有任何 update 查询,但 foreign key 设置为 NULL。

mysql> select * from Phone;
+----+----------+-------------+------+-----------+
| id | areaCode | phoneNumber | type | parent_id |
+----+----------+-------------+------+-----------+
|  1 |      613 | 792-0000    | home |      NULL |
|  2 |      613 | 896-1234    | work |      NULL |
|  3 |      416 | 123-4444    | work |      NULL |
+----+----------+-------------+------+-----------+

我该如何解决这个问题?请让我知道我在哪里犯了错误。

场景 2:

现在,如果我在Employee 表中更改我的@JoinColumn,如下所示:

@JoinColumn(name = "parent_id")

然后 Hibernate 生成 **insert** 然后 update 查询以正确映射外键。

Hibernate: insert into Employee (firstName, lastName, salary) values (?, ?, ?)
Hibernate: insert into Phone (areaCode, phoneNumber, type, id) values (?, ?, ?, ?)
Hibernate: insert into Phone (areaCode, phoneNumber, type, id) values (?, ?, ?, ?)
Hibernate: insert into Phone (areaCode, phoneNumber, type, id) values (?, ?, ?, ?)
Hibernate: update Phone set parent_id=? where id=?
Hibernate: update Phone set parent_id=? where id=?

当 Hibernate 在 Employee 表上运行 insert 时,它自己会在那里获得 employee id,那么当 Hibernate 通过包含外键值?

我知道在update 查询中它正在添加外键,但我想知道为什么这不是在电话表上的insert 查询本身中管理的。你能解释一下吗?

场景 3:

如果我这样说:

@JoinColumn(name = "OWNER_ID", insertable=false, updatable=false, nullable=false)

然后我得到以下异常:

Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value : onetomany.Phone._phones_OWNER_IDBackref

【问题讨论】:

请参考链接***.com/questions/35223952/…和***.com/questions/22591684/… 对于场景 1) 和 3),您指定了 insertable=false, updatable=false,因此不保存这些值的原因很明显。对于场景 2),正如@NitinPrabhu 已经指出的那样,这些问题的重复。 @DraganBozanovic,你能告诉我们什么时候需要使用insertable=false, updatable=false 吗? 【参考方案1】:

你有一个员工和一个电话。

您希望将 insertable=false、updatable=false 添加到与 Phone 实体中的 Employee 实体的 @OneToMany 关系,因为创建或更新 Employee 不是 Phone 实体的责任。反之亦然。

@Entity
public class Employee 

    @Id
    @GeneratedValue
    private long id;

    private String firstName;
    private String lastName;
    private double salary;

    @OneToMany(mappedBy="person", cascade=CascadeType.ALL)
    private List<Phone> phones = new ArrayList<Phone>(0);

    // Setters & Getter methods



@Entity
public class Phone 

    @Id
    private long id;
    private String type;
    private int areaCode;
    private String phoneNumber;

    @ManyToOne
    @JoinColumn(name="PHONE_FK")
    @Column(insertable=false, updatable=false)
    private Employee employee;


【讨论】:

@JoinColumn@Column 不能在 JPA 中一起使用。你会得到一个运行时异常。更多信息请参考:***.com/questions/4121485/…

以上是关于如何避免在一对多单向关联中插入和更新查询的主要内容,如果未能解决你的问题,请参考以下文章

Doctrine - 从反面查询一对多、单向的连接表关联

JPA中实现单向一对多的关联关系

JPA 单向一对多关联关系

Hibernate—— 一对多 和 多对多关联关系映射(xml和注解)总结(转载)

hibernate学习四 hibernate关联关系映射

Hibernate单向“一对多”关联