gpt4 book ai didi

java - Hibernate:orphanRemoval 不适用于克隆的对象

转载 作者:行者123 更新时间:2023-11-30 12:07:32 28 4
gpt4 key购买 nike

我在使用 hibernate 持久化克隆对象时遇到了问题。当它的嵌套子项被删除时,记录并没有从数据库中删除(我已经设置了 orphanRemoval = true)。

在下面的代码中,使用 json 创建了一个克隆。在 clone.removeItem() 之后,hibernate 应该在 session.update(clone) 时删除孤立的 Item。但是当我再次查询时它仍然存在。怎么了?

import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;


public class JacksonTest {

SessionFactory factory;

@BeforeClass
public void setup() {

StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
factory = new MetadataSources(registry)
.addAnnotatedClass(PurchaseOrder.class)
.addAnnotatedClass(Item.class)
.buildMetadata()
.buildSessionFactory();

PurchaseOrder order = new PurchaseOrder(10, LocalDate.now());
order.addItem(new Item(1, "ABC", new BigDecimal("84.50")));

try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();
session.save(order);
tx.commit();
}
}


@AfterMethod
public void shutdown() {
try (Session session = factory.openSession()) {
PurchaseOrder obj = this.findOrder(session, 10);
Transaction tx = session.beginTransaction();
session.delete(obj);
tx.commit();
}

factory.close();
}


@Test
public void testOrphanDelete() {

PurchaseOrder clone;
try (Session session = factory.openSession()) {
PurchaseOrder obj = this.findOrder(session, 10);
session.evict(obj);

clone = this.jsonClone(obj);
assertEquals(clone.getId(), 10); //passed
}

clone.removeItem(clone.getItems().get(0));

try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();
assertEquals(clone.getItems().size(), 0); //passed
session.update(clone);
tx.commit();
}

try (Session session = factory.openSession()) {
PurchaseOrder obj = this.findOrder(session, 10);
//AssertionError: expected [0] but found [1]
assertEquals(obj.getItems().size(), 0);
}

}

private PurchaseOrder findOrder(Session session, int id) {
Query query = session.createQuery("from PurchaseOrder r "
+ "where r.id=:id");
query.setParameter("id", id);
return (PurchaseOrder) query.uniqueResult();
}


private PurchaseOrder jsonClone(PurchaseOrder order) {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

try {
String s = mapper.writeValueAsString(order);
return mapper.readValue(s, PurchaseOrder.class);
} catch (IOException e) {
e.printStackTrace();
return null;
}

}

}

PurchaseOder.java:

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.*;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(
generator=ObjectIdGenerators.PropertyGenerator.class,
property="id")
@Entity
@Access(AccessType.FIELD)
public class PurchaseOrder {

@Id
private int id;
private LocalDate issueDate;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "order")
private List<Item> items = new ArrayList<>();

PurchaseOrder(){}

public PurchaseOrder(int id, LocalDate issueDate) {
this.id = id;
this.issueDate = issueDate;
}


final int getId() {
return id;
}

public final LocalDate getIssueDate() {
return issueDate;
}


final List<Item> getItems() {
return items;
}

public void addItem(Item item) {
item.setOrder(this);
items.add(item);
}

public void removeItem(Item item) {
item.setOrder(null);
items.remove(item);
}
}

项目.java:

import java.math.BigDecimal;
import javax.persistence.*;

@Entity
@Access(AccessType.FIELD)
public class Item {

@Id
private int id;
private String name;
private BigDecimal price;

@ManyToOne(fetch = FetchType.EAGER)
private PurchaseOrder order;

Item(){}

Item(int id, String name, BigDecimal price) {
this.id = id;
this.name = name;
this.price = price;
}


final int getId() {
return id;
}

final String getName() {
return name;
}

final BigDecimal getPrice() {
return price;
}

final PurchaseOrder getOrder() {
return order;
}

final void setOrder(PurchaseOrder order) {
this.order = order;
}

}

hibernate .cfg.xml:

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:D:/test</property>
<property name="connection.username">sa</property>
<property name="connection.password">sa</property>

<property name="hibernate.default_schema">PUBLIC</property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.H2Dialect</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>

</session-factory>

</hibernate-configuration>

最后是我的版本号:
Java: 8 update181
hibernate :5.1.6
jackson :2.9.8
H2数据库:1.4.197

更新:问题仅针对孤儿移除。 Item child 的克隆更新或添加工作正常。因此,此测试没有失败:

    @Test
public void testItemAdding() {

PurchaseOrder clone;
try (Session session = factory.openSession()) {
PurchaseOrder obj = this.findOrder(session, 10);
session.evict(obj);

clone = this.jsonClone(obj);
}

clone.setIssueDate(LocalDate.of(1999, 9, 9));
clone.addItem(new Item(2, "XYZ", new BigDecimal("182.50")));

try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();
session.update(clone);
tx.commit();
}

try (Session session = factory.openSession()) {
PurchaseOrder obj = this.findOrder(session, 10);
assertEquals(obj.getIssueDate(), LocalDate.of(1999, 9, 9));
assertEquals(obj.getItems().size(), 2);
assertEquals(obj.getItems().get(1).getName(), "XYZ");
}
}

最佳答案

对象 clone 不受 jpa 管理,因为它处于 detached 状态。您需要先持久化它才能看到映射所做的更改。

关于java - Hibernate:orphanRemoval 不适用于克隆的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54848103/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com