[英]Persisting Map<Entity, Integer> with @ElementCollection (JPA)
I'm trying to learn more about java persistance api.我正在尝试了解有关 java 持久性 api 的更多信息。
In my test maven project i'm trying to persist the following class:在我的测试 maven 项目中,我试图坚持以下 class:
@Entity
@Table(name = "component")
public class DishComponent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
private int id;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "component_supplement", joinColumns =
@JoinColumn(name="component_id"))
@Column(name = "quantity")
@MapKeyJoinColumn(name = "supplement_id", referencedColumnName = "id")
private Map<Supplement, Integer> supplements;
}
into H2 database.进入H2数据库。
Supplement class:补充class:
@Entity
public class Supplement {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
private int id;
}
schema.sql:架构.sql:
DROP TABLE IF EXISTS component;
create table component (
id INT PRIMARY KEY auto_increment,
name VARCHAR(255) UNIQUE
);
DROP TABLE IF EXISTS supplement;
create table supplement (
id INT PRIMARY KEY auto_increment,
name VARCHAR(255) UNIQUE
);
drop TABLE IF EXISTS component_supplement;
create TABLE component_supplement (
id INT PRIMARY KEY auto_increment,
supplement_id INT REFERENCES supplement(id),
component_id INT REFERENCES component(id),
quantity INT NOT NULL
);
When I try to persist DishComponent instance into db I get the following error:当我尝试将 DishComponent 实例持久化到 db 中时,出现以下错误:
java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
Test:测试:
@DataJpaTest
@ContextConfiguration(classes = DaoConfig.class)
@TestPropertySource(locations = "/test-application.properties")
@Sql(scripts = "/schema.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
class DishComponentDaoImplTest {
@Autowired
private TestEntityManager em;
@Autowired
private DishComponentDao repo;
@Test
void whenGetById_returnDishComponent() {
String suppName = "supp1";
Supplement supp1 = new Supplement(suppName);
String name = "test";
DishComponent dishComponent = DishComponent.getBuilder(name).addSupplement(supp1, 10).build();
DishComponent persist = em.persist(dishComponent);
em.flush();
DishComponent component = repo.getById(persist.getId());
assertThat(component.getName()).isEqualTo(name);
Map<Supplement, Integer> returnedSup = component.getSupplements();
Integer quantity = returnedSup.get(supp1);
assertThat(quantity).isEqualTo(10);
}
}
What am I doing wrong?我究竟做错了什么?
For this project I'm using spring boot 2.2.1.RELEASE with spring-boot-starter-data-jpa and com.h2database:h2:1.4.198对于这个项目,我使用 spring boot 2.2.1.RELEASE 和 spring-boot-starter-data-jpa 和 com.h2database:h2:1.4.198
em.persist(dishComponent)
does not persist the Supplement object, that needs to be saved first with a separate persist call. em.persist(dishComponent)
不会持久化补充 object,需要先通过单独的持久调用来保存。
Your code is really close to this example so check it out: http://www.java2s.com/Tutorials/Java/JPA/0320__JPA_ElementCollection_MapKeyEntity.htm您的代码非常接近此示例,因此请查看: http://www.java2s.com/Tutorials/Java/JPA/0320__JPA_ElementCollection_MapKeyEntity.htm
You mappings are valid but unusual ( @ElementCollection
is normally used with a collection of embeddables and not entities however it can be used as you have here).您的映射是有效但不寻常的(
@ElementCollection
通常与可嵌入的集合而不是实体一起使用,但它可以像您在这里一样使用)。
From the tables you have a many-to-many between component and supplement.从表格中,您可以在组件和补充之间找到多对多。 However as you want to store an additional property on the relationship -
quantity
- you will need a 3rd entity for the join.但是,由于您想在关系上存储一个附加属性 -
quantity
- 您将需要第三个实体来进行连接。
I don not see that mapping as you have it can fit your table structure.我没有看到您拥有的映射可以适合您的表结构。
The following is a more 'standard' way of mapping such a relationship and allows for greater flexibility and fits your table structure.以下是映射此类关系的更“标准”方式,并允许更大的灵活性并适合您的表结构。
Component Entity:组件实体:
@Entity
public class Component {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
private Long id;
@OneToMany(mappedBy = "component")
private Set<ComponentSupplement> suplements;
}
Supplement Entity:补充实体:
@Entity
public class Supplement {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
private Long id;
@OneToMany(mappedBy = "supplement")
private Set<ComponentSupplement> suplements;
}
'Join' Entity: “加入”实体:
@Entity
@Table(name = "component_supplement")
public class ComponentSupplement {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
private int id;
@ManyToOne(cascase = Cascadetype.ALL)
@JoinColumn(name = "component_id")
private Component component;
@ManyToOne(cascase = Cascadetype.ALL)
@JoinColumn(name = "supplement_id")
private Supplement supplement;
private int quantity;
}
Construct and Save:构建和保存:
Component component = new Component();
Supplement supplement = new Supplement();
ComponentSupplement cs = new ComponentSupplement();
cs.setComponent(component);
cs.setSupplement(supplement);
em.persist(cs);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.