单个事务中的多个 Spring Data JPA 存储库
Multiple Spring Data JPA repositories in single transaction
我正在尝试映射以下代码:
* Order包含很多OrderItems
* Article can be referenced by (contains) many OrderItems
在一次交易中,我需要创建订单、几篇文章和包含新文章的 OrderItems。当有直线路径时一切都很清楚 - 订单包含 OrderItems 等等 - 然后我可以调用
orderRepository.save(order);
orderRepository.flush();
包含 OrderItems 实体的新订单实体已保存。问题也始于尝试保存 Article 实体。显然需要做更多的工作,因为我收到了错误消息;
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
如何在一笔交易中组织这样的工作?多个存储库是否可以在单个事务下工作,如果是这样 - 谁的 flush() 完成事务。是否需要多次刷新(例如,一个用于文章实体,另一个用于订单),如果需要,如何回滚所有这些?
显然不可能将存储库与简单的 EntityManager.getTransaction().{begin(), commit()} 代码混合,因为这样错误消息是:
java.lang.IllegalStateException: Cannot obtain local EntityTransaction from a transaction-synchronized EntityManager
如果一个实体 (OrderItem) 由两个实体(Order 和 Article)所有并且所有三个实体都应在一个事务中创建,那么最佳做法是什么?
添加了部分代码。 completeOrder 是测试程序,其中为新订单创建了 5 个项目和 5 个新文章。此过程给出异常 "references and unsaved transient instance"。我正在为 Article 实体使用复合键,但这应该不是问题,我现在正在尝试与具有通常的单字段键的 Article 实体相同的场景。
@Entity
public class Order extends FrameworkEntity {
...
@OneToMany(mappedBy="order", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<OrderItem>();
}
@Entity
public class OrderItem extends FrameworkEntity {
...
@ManyToOne
@JoinColumn(name="fk_order")
private Order order;
@ManyToOne
@JoinColumns({
@JoinColumn(name="fk_date"),
@JoinColumn(name="fk_number")
})
private Article article;
}
@Entity
public class Article extends FrameworkEntity {
...
@Id
protected PkArticle pkArticle;
@OneToMany(mappedBy="article", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<OrderItem>();
}
@Embeddable
public class PkArticle extends FrameworkCompositeKey {
@Column(name = "article_number")
private Long articleNumber;
@Temporal(TemporalType.DATE)
@Column(name = "article_date")
private Date articleDate;
...
}
public class OrderService {
public void completeOrder() {
Order entity = new Order();
for (int i=0; i<5; i++) {
Date articleDate;
Long articleNumber;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.set(2015, 1, 31, 0, 0, 0);
articleDate = cal.getTime();
articleNumber = (new Random()).nextLong();
Article article = new Article(articleNumber, articleDate);
//entityManager.getTransaction().begin();
//entityManager.persist(space);
//entityManager.getTransaction().commit();
OrderItem item = new OrderItem();
item.setArticle(article);
article.getOrderItems().add(item);
item.setOrder(entity);
entity.getOrderItems().add(item);
}
entity=(Order) repository.save(entity);
repository.flush();
}
]
你有这样的代码吗?
@Entity
public class OrderItem {
@ManyToOne
private Article article;
}
如果是,请将其更改为:
@Entity
public class OrderItem {
@ManyToOne(cascade = CascadeType.PERSIST)
private Article article;
}
这将确保当一个新的 OrderItem
和一个尚未保存的 Article
被持久化时,Article
也会被保存。
我正在尝试映射以下代码: * Order包含很多OrderItems * Article can be referenced by (contains) many OrderItems
在一次交易中,我需要创建订单、几篇文章和包含新文章的 OrderItems。当有直线路径时一切都很清楚 - 订单包含 OrderItems 等等 - 然后我可以调用
orderRepository.save(order);
orderRepository.flush();
包含 OrderItems 实体的新订单实体已保存。问题也始于尝试保存 Article 实体。显然需要做更多的工作,因为我收到了错误消息;
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
如何在一笔交易中组织这样的工作?多个存储库是否可以在单个事务下工作,如果是这样 - 谁的 flush() 完成事务。是否需要多次刷新(例如,一个用于文章实体,另一个用于订单),如果需要,如何回滚所有这些?
显然不可能将存储库与简单的 EntityManager.getTransaction().{begin(), commit()} 代码混合,因为这样错误消息是:
java.lang.IllegalStateException: Cannot obtain local EntityTransaction from a transaction-synchronized EntityManager
如果一个实体 (OrderItem) 由两个实体(Order 和 Article)所有并且所有三个实体都应在一个事务中创建,那么最佳做法是什么?
添加了部分代码。 completeOrder 是测试程序,其中为新订单创建了 5 个项目和 5 个新文章。此过程给出异常 "references and unsaved transient instance"。我正在为 Article 实体使用复合键,但这应该不是问题,我现在正在尝试与具有通常的单字段键的 Article 实体相同的场景。
@Entity
public class Order extends FrameworkEntity {
...
@OneToMany(mappedBy="order", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<OrderItem>();
}
@Entity
public class OrderItem extends FrameworkEntity {
...
@ManyToOne
@JoinColumn(name="fk_order")
private Order order;
@ManyToOne
@JoinColumns({
@JoinColumn(name="fk_date"),
@JoinColumn(name="fk_number")
})
private Article article;
}
@Entity
public class Article extends FrameworkEntity {
...
@Id
protected PkArticle pkArticle;
@OneToMany(mappedBy="article", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<OrderItem>();
}
@Embeddable
public class PkArticle extends FrameworkCompositeKey {
@Column(name = "article_number")
private Long articleNumber;
@Temporal(TemporalType.DATE)
@Column(name = "article_date")
private Date articleDate;
...
}
public class OrderService {
public void completeOrder() {
Order entity = new Order();
for (int i=0; i<5; i++) {
Date articleDate;
Long articleNumber;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.set(2015, 1, 31, 0, 0, 0);
articleDate = cal.getTime();
articleNumber = (new Random()).nextLong();
Article article = new Article(articleNumber, articleDate);
//entityManager.getTransaction().begin();
//entityManager.persist(space);
//entityManager.getTransaction().commit();
OrderItem item = new OrderItem();
item.setArticle(article);
article.getOrderItems().add(item);
item.setOrder(entity);
entity.getOrderItems().add(item);
}
entity=(Order) repository.save(entity);
repository.flush();
}
]
你有这样的代码吗?
@Entity
public class OrderItem {
@ManyToOne
private Article article;
}
如果是,请将其更改为:
@Entity
public class OrderItem {
@ManyToOne(cascade = CascadeType.PERSIST)
private Article article;
}
这将确保当一个新的 OrderItem
和一个尚未保存的 Article
被持久化时,Article
也会被保存。