jpa vue管理系统_使用Hibernate(JPA)一键式删除

jpa vue管理系统

jpa vue管理系统

在旧版本的Hibernate中,我可以看到手册中指示的一键式删除。 但是较新的版本不再包含此部分。 我不知道为什么。 因此,在这篇文章中,我来看看它是否仍然有效。

一键式删除部分显示:

有时一个接一个地删除收集元素可能效率极低。 对于新的空集合(例如,如果您调用list.clear() ,Hibernate不会这样做。 在这种情况下,Hibernate将发出一个DELETE

假设您向大小为20的集合中添加了一个元素,然后删除了两个元素。 除非集合是一个包,否则Hibernate将发出一个INSERT语句和两个DELETE语句。 这当然是可取的。

但是,假设我们删除了18个元素,剩下两个,然后添加了新元素。 有两种可能的方式进行

  • 一一删除十八行,然后再插入三行
  • 在一个SQL DELETE删除整个集合,并一一插入所有五个当前元素

Hibernate不知道第二个选项可能更快。 Hibernate如此直观可能会不受欢迎,因为这种行为可能会混淆数据库触发器等。

幸运的是,您可以通过丢弃(即取消引用)原始集合并返回带有所有当前元素的新实例化集合,来随时强制执行此行为(即第二种策略)。

一击删除不适用于映射为inverse="true"集合。

inverse="true"适用于(Hibernate映射)XML。 但是在这篇文章中,我们将看到JPA (以Hibernate为提供者)如何进行“一次性删除”。

我们将尝试不同的方法,看看哪种方法会导致一次删除。

  1. 双向一对多
  2. 单向一对多(带连接表)
  3. 单向一对多(无连接表)
  4. 单向一对多(使用ElementCollection )

我们将使用具有多个CartItemCart实体。

双向一对多

对于这一点,我们从双方的引用。

@Entity
public class Cart { ...
 @OneToMany(mappedBy="cart", cascade=ALL, orphanRemoval=true)
 Collection<OrderItem> items;
}

@Entity
public class CartItem { ...
 @ManyToOne Cart cart;
}

为了测试这一点,我们为Cart的表插入一行,为CartItem的表插入三行或更多行。 然后,我们运行测试。

public class CartTests { ...
 @Test
 public void testOneShotDelete() throws Exception {
  Cart cart = entityManager.find(Cart.class, 53L);
  for (CartItem item : cart.items) {
   item.cart = null; // remove reference to cart
  }
  cart.items.clear(); // as indicated in Hibernate manual
  entityManager.flush(); // just so SQL commands can be seen
 }
}

所示SQL命令将每个项目分别删除(而不是一次性删除)。

delete from CartItem where id=?
delete from CartItem where id=?
delete from CartItem where id=?

丢弃原始集合也不起作用。 它甚至引起了异常。

public class CartTests { ...
 @Test
 public void testOneShotDelete() throws Exception {
  Cart cart = entityManager.find(Cart.class, 53L);
  // remove reference to cart
  cart.items = new LinkedList<CartItem>(); // discard, and use new collection
  entityManager.flush(); // just so SQL commands can be seen
 }
}
javax.persistence.PersistenceException:
    org.hibernate.HibernateException:
        A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: ….Cart.items

我用Hibernate 4.3.11和HSQL 2.3.2对此进行了测试。 如果您的结果有所不同,请点击评论

单向一对多(带连接表)

为此,我们对映射进行了更改。 这将导致创建一个联接表。

@Entity
public class Cart { ...
 @OneToMany(cascade=ALL)
 Collection<OrderItem> items;
}

@Entity
public class CartItem { ...
 // no @ManyToOne Cart cart;
}

同样,对于Cart ,我们在表中插入一行,对于CartItem ,我们在表中插入三行或更多行。 我们还必须在连接表( Cart_CartItem )中插入适当的记录。 然后,我们运行测试。

public class CartTests { ...
 @Test
 public void testOneShotDelete() throws Exception {
  Cart cart = entityManager.find(Cart.class, 53L);
  cart.items.clear(); // as indicated in Hibernate manual
  entityManager.flush(); // just so SQL commands can be seen
 }
}

显示SQL命令已删除联接表中的关联行(使用一个命令)。 但是表中CartItem的行仍然存在(并且没有被删除)。

delete from Cart_CartItem where cart_id=?
// no delete commands for CartItem

嗯,不完全是我们想要的,因为CartItem表中的行仍然存在。

单向一对多(无联接表)

从JPA 2.0开始,通过指定@JoinColumn可以避免单向一对多的连接表。

@Entity
public class Cart { ...
 @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
 @JoinColumn(name="cart_id", updatable=false, nullable=false)
 Collection<OrderItem> items;
}

@Entity
public class CartItem { ...
 // no @ManyToOne Cart cart;
}

同样,对于Cart ,我们在表中插入一行,对于CartItem ,我们在表中插入三行或更多行。 然后,我们运行测试。

public class CartTests { ...
 @Test
 public void testOneShotDelete() throws Exception {
  Cart cart = entityManager.find(Cart.class, 53L);
  cart.items.clear(); // as indicated in Hibernate manual
  entityManager.flush(); // just so SQL commands can be seen
 }
}

丢弃原始收藏集也无效。 这也导致了相同的异常(与双向一对多)。

javax.persistence.PersistenceException:
    org.hibernate.HibernateException:
        A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: ….Cart.items

单向一对多(带有

JPA 2.0引入了@ElementCollection 。 这允许与许多侧之中任建立一个一对多关系@Basic@Embeddable (即不是@Entity )。

@Entity
public class Cart { ...
 @ElementCollection // @OneToMany for basic and embeddables
 @CollectionTable(name="CartItem") // defaults to "Cart_items" if not overridden
 Collection<OrderItem> items;
}

@Embeddable // not an entity!
public class CartItem {
 // no @Id
 // no @ManyToOne Cart cart;
 private String data; // just so that there are columns we can set
}

同样,对于Cart ,我们在表中插入一行,对于CartItem ,我们在表中插入三行或更多行。 然后,我们运行测试。

public class CartTests { ...
 @Test
 public void testOneShotDelete() throws Exception {
  Cart cart = entityManager.find(Cart.class, 53L);
  cart.items.clear(); // as indicated in Hibernate manual
  entityManager.flush(); // just so SQL commands can be seen
 }
}

是的CartItem的关联行被CartItem删除。

delete from CartItem where Cart_id=?

总结思想

使用ElementCollection进行单向一对多删除(其中ElementCollection是可嵌入的,而不是实体)。

在具有连接表的单向一对多方案中,删除连接表中的条目不会增加太多价值。

我不确定为什么一键式删除在Hibernate中起作用(或为什么这样起作用)。 但是我确实有一个猜测。 那就是底层的JPA提供者不能一次性删除,因为它不能确保多端实体不会被其他实体引用。 与ElementCollection不同,多面不是实体,其他实体也不能引用。

现在,这并不意味着您必须一直使用ElementCollection 。 一次性删除可能仅适用于聚合根。 在这些情况下,使用EmbeddableElementCollection可能适合于组成聚合的值对象的集合。 当除去聚合根时,最好也应除去“子”对象(并以有效的方式)。

我希望JPA中有一种方法可以指示子实体是私有的,并且在删除父实体时可以安全地删除它们(例如,类似于EclipseLink中的@PrivateOwned )。 让我们看看它是否将包含在API的将来版本中。

希望这可以帮助。

翻译自: https://www.javacodegeeks.com/2016/07/one-shot-delete-hibernate-jpa.html

jpa vue管理系统

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值