Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JPA/Hibernate-如何从一个没有引用要级联到的实体级联删除?_Hibernate_Jpa - Fatal编程技术网

JPA/Hibernate-如何从一个没有引用要级联到的实体级联删除?

JPA/Hibernate-如何从一个没有引用要级联到的实体级联删除?,hibernate,jpa,Hibernate,Jpa,我在Hibernate中使用JPA 我有一个用户类和一个标志类: class User { // ... } class Flag { @OneToOne(optional=false) private User user; } 我不想/不需要对User类中的Flag对象的引用(这是要点)。但是当我删除一个用户时,我希望关联的标志(如果有)也被删除,没有任何外键约束失败异常 我知道我可以在用户内部添加对标志的引用,如: class User { @OneTo

我在Hibernate中使用JPA

我有一个用户类和一个标志类:

class User
{
    // ...
}

class Flag
{
    @OneToOne(optional=false)
    private User user;

}
我不想/不需要对User类中的Flag对象的引用(这是要点)。但是当我删除一个用户时,我希望关联的标志(如果有)也被删除,没有任何外键约束失败异常

我知道我可以在用户内部添加对标志的引用,如:

class User
{
    @OneToOne(optional=true, cascade=CascadeType.ALL, mappedBy="user")
    @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private Flag flag;
}
然后,当我删除用户时,Flag对象将被删除

但是,是否可以级联删除该标志而不在用户中引用它


如果没有,如果删除此类对象的正确方法是什么?

您无法自动级联删除。在这种情况下,您需要实现自己的删除

删除用户时,首先运行如下查询:

delete from Flag F where F.userId = :userId

你没有说你正在使用哪个数据库,所以我假设它是MySQL

这些是我们的桌子。注意用户标识和用户标志标识之间的一对一映射,以及更新级联子句上的on delete级联

鉴于这些,您可以创建如下映射

@Entity(name = "user")
@Table(schema = "test", name = "user")
public final class User {

  @Id
  @Column(name = "user_id")
  public int id;

  @Basic
  @Column(name = "user_name")
  public String name;
}

@Entity(name = "user_flag")
@Table(schema = "test", name = "user_flag")
public final class UserFlag {

  @Id
  @Column(name = "user_flag_id")
  public int id;

  @Basic
  @Column(name = "user_flag_name")
  public String name;

  @OneToOne
  @JoinColumn(name = "user_flag_id", referencedColumnName = "user_id")
  public User user;
}
假设我们有以下数据

+---------+-----------+
| user_id | user_name |
+---------+-----------+
|       1 | Joe       |
|       2 | Jane      |
|       3 | Jacob     |
+---------+-----------+

+--------------+----------------+
| user_flag_id | user_flag_name |
+--------------+----------------+
|            1 | Joe's flag     |
|            3 | Jacob's flag   |
+--------------+----------------+
下面的代码将演示,如果您删除一个用户,其关联的标志将被删除(但不是相反)


本例假设您选择的引擎是InnoDB。但是,如果您想使用MyISAM,您可以。

是否有单独的用户和标志表?它们看起来怎么样?您在上一个示例中使用了@OneToOne注释,这向我表明,每个唯一用户都可以有一个与之关联的唯一标志。这看起来很奇怪(如果你有单独的桌子,就是说)。你想解释一下你想用这些来达到什么目的吗?我觉得这对你自己来说很难。无论如何,在没有引用的情况下,最好是在表级别使用触发器或指定{delete,update}级联。Flag类实际上只是一个例子。一个更接近我的实际应用程序的例子是“ContactRequest”实体:用户可以创建一个(并且只有一个)ContactRequest。在管理员联系用户之前,ContactRequest实例将存在于数据库中。但是,如果用户创建了一个ContactRequest,然后删除了他的帐户,我希望与用户相关的所有内容也被删除,而不会出现“外键约束失败”的异常。另外:当你说“我可以在表级别使用触发器”时,你的意思是在数据库本身中,而不是在JPA中,对吗?谢谢MattR。我将标记这一点,因为答案是没有人会提出其他建议。Róbert,我理解您建议在表级别管理级联过程。但是,在处理JPA应用程序时,这是一种好的/标准的做法吗?将一些级联作为注释来管理,而将其他级联作为数据库本身来管理,这难道不容易吗?如果您使用任何类型的hibernate实体/查询的内存缓存,您不会希望这样做-hibernate不知道该标志已被删除,因此它仍然存在于缓存中(至少在某个超时之前)@电打字会让人困惑吗?是的,但你没有问你想做的事情是否令人困惑。我试图在我的第一个评论中暗示,你将要做的事情看起来很奇怪,事实证明你已经看到了。如果您有其他实体以JPA方式处理关系,那么我看不出您为什么要隐藏此特定关系。在我的解决方案中,Hibernate的缓存只有在用户数量非常多的情况下才会出现问题。在双方声明关系,但在用户端限制访问。“在双方声明关系,但在用户端限制访问。”:这是我实际要做的。我认为这是管理级联的最干净的方法。我只是不想在用户类中为它添加任何getter/setter。但是,在我看来,对我最初的问题最好的答案是马特的答案。我不喜欢将级联作为注释和表级别进行管理的想法。谢谢罗伯特的帮助!
+---------+-----------+
| user_id | user_name |
+---------+-----------+
|       1 | Joe       |
|       2 | Jane      |
|       3 | Jacob     |
+---------+-----------+

+--------------+----------------+
| user_flag_id | user_flag_name |
+--------------+----------------+
|            1 | Joe's flag     |
|            3 | Jacob's flag   |
+--------------+----------------+
@Test
public void test() {
  EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
  EntityManager em = emf.createEntityManager();
  EntityTransaction et = em.getTransaction();

  // prints out our three users, Joe, Jane and Jacob
  for (User u : em.createQuery(String.format("select u from %s u", User.class.getName()), User.class)
      .getResultList())
    System.out.format("User{id=%s, name=%s}\n", u.id, u.name);

  // prints out Joe's and Jacob's flags
  for (UserFlag uf : em.createQuery(String.format("select uf from %s uf", UserFlag.class.getName()), UserFlag.class)
      .getResultList())
    System.out.format("UserFlag{id=%s, name=%s}\n", uf.id, uf.name);

  et.begin();
  User jacob = em.find(User.class, 3);
  em.remove(jacob);
  et.commit();

  // prints out our remaining users, Joe and Jane
  for (User u : em.createQuery(String.format("select u from %s u", User.class.getName()), User.class)
      .getResultList())
    System.out.format("User{id=%s, name=%s}\n", u.id, u.name);

  // prints out Joe's flag
  for (UserFlag uf : em.createQuery(String.format("select uf from %s uf", UserFlag.class.getName()), UserFlag.class)
      .getResultList())
    System.out.format("UserFlag{id=%s, name=%s}\n", uf.id, uf.name);

  em.close();
  emf.close();
}