将 @ElementCollection 移动到 @Embeddable 类中不起作用。

huangapple go评论78阅读模式
英文:

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&lt;MyEntityId&gt; {
  @ElementCollection
  @OrderColumn
  private List&lt;Double&gt; doubles;
}

But this does not:

@Entity
public class MyEntity extends AbstractEntity&lt;MyEntityId&gt; {
  @Embedded
  private Doubles doubles;
}

@Embeddable
public class Doubles {
  @ElementCollection
  @OrderColumn
  private List&lt;Double&gt; 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&lt;Double&gt; doubles = new ArrayList&lt;&gt;();
}

答案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, &#39;CL1&#39;), (1, 0, &#39;CL2&#39;);

and the following mapping:

@Entity
@Table(name = &quot;T1_MY_ENTITY&quot;)
public class MyEntity
{
   @Id
   @Column(name = &quot;tm_id&quot;)
   private Long id;

   @Embedded
   private Doubles dou;
   
   // constructor, getters, setters
}

@Embeddable
public class Doubles
{
   @OrderColumn(name = &quot;tc_ord_id&quot;)
   @ElementCollection
   @CollectionTable(name = &quot;T1_MY_COLL&quot;, joinColumns = @JoinColumn(name = &quot;tc_tm_id&quot;))
   @Column(name = &quot;tc_code&quot;)
   private List&lt;String&gt; colls;

   // constructor, getters, setters
}

the following code:

MyEntity myEntity =  entityManager.find(MyEntity.class, 1L);
myEntity.getDou().getColls().add(&quot;CL5&quot;);
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(&quot;SELECT count(*) FROM my_entity2_doubles&quot;, Long.class)).isEqualTo(2);
}

huangapple
  • 本文由 发表于 2020年10月13日 21:57:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/64336648.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定