英文:
Moving @ElementCollection to @Embeddable class not working
问题
我正在尝试将我@Entity
类中的一个带有@ElementCollection
注释的字段移动到另一个使用@Embeddable
注解的类中。当该字段位于实体中时,Hibernate将生成适当的INSERT语句。但是,当该字段移动到@Embeddable
类中时,不会生成任何INSERT语句。
因此,这段代码有效:
@Entity
public class MyEntity extends AbstractEntity<MyEntityId> {
@ElementCollection
@OrderColumn
private List<Double> doubles;
}
但是,这段代码无效:
@Entity
public class MyEntity extends AbstractEntity<MyEntityId> {
@Embedded
private Doubles doubles;
}
@Embeddable
public class Doubles {
@ElementCollection
@OrderColumn
private List<Double> doubles;
}
在保存MyEntity
实例(并刷新EntityManager)时不会出现异常。如果我禁用Flyway中的相应表的创建,Hibernate验证会触发“缺少表[my_entity_doubles]”错误,因此Hibernate似乎正确解释了这个设置。
使用使用Hibernate 5.4.21的Spring Boot 2.3.4。
更新:可在https://github.com/wimdeblauwe/so-64336648找到可重现的测试案例。
英文:
I am trying to move an @ElementCollection
annotated field from my @Entity
class into a different class that I annotated with @Embeddable
. When the field is in the entity, Hibernate will issue the proper INSERT statements. When the field is moved to the @Embeddable
class, no INSERT statements are generated.
So this works:
@Entity
public class MyEntity extends AbstractEntity<MyEntityId> {
@ElementCollection
@OrderColumn
private List<Double> doubles;
}
But this does not:
@Entity
public class MyEntity extends AbstractEntity<MyEntityId> {
@Embedded
private Doubles doubles;
}
@Embeddable
public class Doubles {
@ElementCollection
@OrderColumn
private List<Double> doubles;
}
There is no exception when saving a MyEntity
instance (and flushing the EntityManager). If I disable creating the appropriate table in Flyway, the Hibernate validation does trigger a "missing table [my_entity_doubles]" error, so Hibernate does seem to correct interpret the setup.
Using Spring Boot 2.3.4 that uses Hibernate 5.4.21.
UPDATE: There is a reproducible testcase at https://github.com/wimdeblauwe/so-64336648
答案1
得分: 1
我不知道为什么。但是使用集合赋值有效。
@Embeddable
public class Doubles {
@ElementCollection
private List<Double> doubles = new ArrayList<>();
}
英文:
I don't know why. But assigning with a collection works.
@Embeddable
public class Doubles {
@ElementCollection
private List<Double> doubles = new ArrayList<>();
}
答案2
得分: 0
按照JPA规范中所述(见 2.5 Embeddable Classes 部分):
> 嵌入式类(包括另一个嵌入式类内的嵌入式类)可以包含基本类型或其他嵌入式类的集合。嵌入式类之间存在直接或间接的循环包含依赖关系是不允许的。
并举一个基于 Hibernate 5.4.21 的简单示例。
假设我们有以下模式:
create table T1_MY_ENTITY
(
tm_id int not null,
primary key (tm_id)
);
insert into T1_MY_ENTITY values (1);
create table T1_MY_COLL
(
tc_tm_id int not null,
tc_ord_id int not null,
tc_code varchar(100),
foreign key (tc_tm_id) references T1_MY_ENTITY(tm_id)
);
insert into T1_MY_COLL values (1, 1, 'CL1'), (1, 0, 'CL2');
以及以下映射:
@Entity
@Table(name = "T1_MY_ENTITY")
public class MyEntity
{
@Id
@Column(name = "tm_id")
private Long id;
@Embedded
private Doubles dou;
// constructor, getters, setters
}
@Embeddable
public class Doubles
{
@OrderColumn(name = "tc_ord_id")
@ElementCollection
@CollectionTable(name = "T1_MY_COLL", joinColumns = @JoinColumn(name = "tc_tm_id"))
@Column(name = "tc_code")
private List<String> colls;
// constructor, getters, setters
}
以下代码:
MyEntity myEntity = entityManager.find(MyEntity.class, 1L);
myEntity.getDou().getColls().add("CL5");
entityManager.merge(myEntity);
将生成插入操作:
19:51:29,612 DEBUG SQL:128 -
/* insert collection
row com.my.hibernate.entities.MyEntity.dou.colls */ insert
into
TEST_SCHEMA.T1_MY_COLL
(tc_tm_id, tc_ord_id, tc_code)
values
(?, ?, ?)
Hibernate:
/* insert collection
row com.my.hibernate.entities.MyEntity.dou.colls */ insert
into
TEST_SCHEMA.T1_MY_COLL
(tc_tm_id, tc_ord_id, tc_code)
values
(?, ?, ?)
19:51:29,612 TRACE ResourceRegistryStandardImpl:83 - Registering statement [/* insert collection row com.my.hibernate.entities.MyEntity.dou.colls */ insert into TEST_SCHEMA.T1_MY_COLL (tc_tm_id, tc_ord_id, tc_code) values (?, ?, ?)]
19:51:29,612 TRACE BasicBinder:64 - binding parameter [1] as [BIGINT] - [1]
19:51:29,613 TRACE BasicBinder:64 - binding parameter [2] as [INTEGER] - [2]
19:51:29,613 TRACE BasicBinder:64 - binding parameter [3] as [VARCHAR] - [CL5]
因此,问题似乎出在其他方面。
更新:关于您的 测试用例,请尝试以下修正方式:
@Test
void test() {
MyEntity2 entity = new MyEntity2();
Doubles doubles = new Doubles();
doubles.setDoubles(List.of(1.0, 1.5));
entity.setDoubles(doubles); // It was absent !!!
repository.save(entity);
entityManager.flush();
assertThat(jdbcTemplate.queryForObject("SELECT count(*) FROM my_entity2_doubles", Long.class)).isEqualTo(2);
}
英文:
As it stated in the JPA specification (see 2.5 Embeddable Classes section):
> An embeddable class (including an embeddable class within another embeddable class) may contain a collection of a basic type or other embeddable class. Direct or indirect circular containment dependencies among embeddable classes are not permitted.
And simple example (based on Hibernate 5.4.21).
Assuming that we have the following schema:
create table T1_MY_ENTITY
(
tm_id int not null,
primary key (tm_id)
);
insert into T1_MY_ENTITY values (1);
create table T1_MY_COLL
(
tc_tm_id int not null,
tc_ord_id int not null,
tc_code varchar(100),
foreign key (tc_tm_id) references T1_MY_ENTITY(tm_id)
);
insert into T1_MY_COLL values (1, 1, 'CL1'), (1, 0, 'CL2');
and the following mapping:
@Entity
@Table(name = "T1_MY_ENTITY")
public class MyEntity
{
@Id
@Column(name = "tm_id")
private Long id;
@Embedded
private Doubles dou;
// constructor, getters, setters
}
@Embeddable
public class Doubles
{
@OrderColumn(name = "tc_ord_id")
@ElementCollection
@CollectionTable(name = "T1_MY_COLL", joinColumns = @JoinColumn(name = "tc_tm_id"))
@Column(name = "tc_code")
private List<String> colls;
// constructor, getters, setters
}
the following code:
MyEntity myEntity = entityManager.find(MyEntity.class, 1L);
myEntity.getDou().getColls().add("CL5");
entityManager.merge(myEntity);
will generate insert:
19:51:29,612 DEBUG SQL:128 -
/* insert collection
row com.my.hibernate.entities.MyEntity.dou.colls */ insert
into
TEST_SCHEMA.T1_MY_COLL
(tc_tm_id, tc_ord_id, tc_code)
values
(?, ?, ?)
Hibernate:
/* insert collection
row com.my.hibernate.entities.MyEntity.dou.colls */ insert
into
TEST_SCHEMA.T1_MY_COLL
(tc_tm_id, tc_ord_id, tc_code)
values
(?, ?, ?)
19:51:29,612 TRACE ResourceRegistryStandardImpl:83 - Registering statement [/* insert collection row com.my.hibernate.entities.MyEntity.dou.colls */ insert into TEST_SCHEMA.T1_MY_COLL (tc_tm_id, tc_ord_id, tc_code) values (?, ?, ?)]
19:51:29,612 TRACE BasicBinder:64 - binding parameter [1] as [BIGINT] - [1]
19:51:29,613 TRACE BasicBinder:64 - binding parameter [2] as [INTEGER] - [2]
19:51:29,613 TRACE BasicBinder:64 - binding parameter [3] as [VARCHAR] - [CL5]
So, It looks like your problem lies in the other plane.
UPDATE: As for your test case, please try to correct it in the following way:
@Test
void test() {
MyEntity2 entity = new MyEntity2();
Doubles doubles = new Doubles();
doubles.setDoubles(List.of(1.0, 1.5));
entity.setDoubles(doubles); // It was absent !!!
repository.save(entity);
entityManager.flush();
assertThat(jdbcTemplate.queryForObject("SELECT count(*) FROM my_entity2_doubles", Long.class)).isEqualTo(2);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论