【问题标题】:Hibernate persists only first nested entityHibernate 只保留第一个嵌套实体
【发布时间】:2020-04-03 09:07:43
【问题描述】:

我的问题是 Hibernate 不保留实体中给定的嵌套实体。

考虑以下实体:

投票实体

@Table(name = "\"poll\"")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@EqualsAndHashCode(of = "id")
@Builder
public class PollEntity {

    @Transient
    public OptionEntity addOption(OptionEntity pollOptionEntity) {
        if(options == null)
            options = new HashSet<>();
        options.add(pollOptionEntity);
        pollOptionEntity.setPoll(this);
        return pollOptionEntity;
    }

    @Transient
    public OptionEntity dropOption(OptionEntity pollOptionEntity) {
        options.remove(pollOptionEntity);
        pollOptionEntity.setPoll(null);
        return pollOptionEntity;
    }

    @Id
    @Column(name = "id")
    private UUID id;
    @Column(name = "author")
    @UUIDv4
    private UUID author;
    @Column(name = "poll_question")
    @Size(max = 1000)
    private String pollQuestion;
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "poll", cascade = CascadeType.MERGE)
    @Builder.Default
    @Valid
    private Set<OptionEntity> options;
}

OptionEntity

@Table(name = "\"option\"")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@EqualsAndHashCode(of = "id")
@Builder
public class OptionEntity {
    @Id
    @GeneratedValue(generator = "UUID")
    @Column(name = "id")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    private UUID id;
    @JoinColumn(name = "poll_id")
    @ManyToOne
    private PollEntity poll;
    @Column(name = "option")
    @Size(max = 1000)
    @NotNull
    private String option;
}

这是服务方法:

@Transactional(rollbackFor = Throwable.class)
public void createPoll(@Valid PollEntity pollEntity) throws ValidationException {
    validationService.validateOrThrow(pollEntity);
    if (pollRepository.findById(pollEntity.getId()).isPresent())
        throw new ValidationException("Invalid id", Map.of("id", "Poll with id (" + pollEntity.getId() + ") already exists"));
    pollEntity = validationService.validateAndSave(pollRepository, pollEntity);

以及相应的测试:

@Test
public void createPollTest() throws ValidationException {
    var uuid = UUID.randomUUID();
    var pollOption1 = OptionEntity.builder()
        .option("Test option 1")
        .build();
    var pollOption2 = OptionEntity.builder()
        .option("Test option 2")
        .build();
    var pollOption3 = OptionEntity.builder()
        .option("Test option 3")
        .build();
    var poll = PollEntity.builder()
        .id(uuid)
        .pollQuestion("Test question")
        .author(UUID.randomUUID())
        .build();
    poll.addOption(pollOption1);
    poll.addOption(pollOption2);
    poll.addOption(pollOption3);
    pollService.createPoll(poll);
}

在数据库中提供以下输出

投票

2e565f50-7cd4-4fc9-98cd-49e0f0964487 feae5781-ff07-4a21-9292-c11c4f1a047d Test question

选项

c786fe5d-632d-4e94-95ef-26ab2af633e7 fc712242-8e87-41d8-93f2-ff0931020a4a Test option 1

其余选项最终没有持久化。

我也习惯在单独的方法中创建选项

@Transactional(propagation= Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public Set<OptionEntity> createOptions(@Valid Set<OptionEntity> pollOptionsEntities) throws ValidationException {
    for (var pollOption : pollOptionsEntities) {
        validationService.validateAndSave(pollOptionsRepository, pollOption);
    }
    return pollOptionsEntities;
}

并且选项实体正在生成,但由于持久轮询实体的错误,不得不从内置实体方法切换到持久化。

数据库架构如下所示:

CREATE TABLE "poll"
(
    "id"            UUID PRIMARY KEY,
    "author"        UUID          NOT NULL,
    "poll_question" VARCHAR(1000) NOT NULL
)

CREATE TABLE "option"
(
    "id"         UUID PRIMARY KEY,
    "poll_id"    UUID          NOT NULL REFERENCES "poll" ("id") ON DELETE CASCADE
    "option"     VARCHAR(1000) NOT NULL
)

有哪些可能的尝试方法?

UPD 1

考虑过各种相似的问题 (1,2,3,4,5)

我想出了对实体的添加,它假设使实体持久化而不管实际值如何,并且在输出中仍然只有一个选项。做错了什么?

@Override
public boolean equals(Object object) {
    if ( object == this ) {
        return false;
    }
    if ( object == null || object.getClass() != getClass() ) {
        return false;
    }
    final OptionEntity other = OptionEntity.class.cast( object );
    if ( getId() == null && other.getId() == null ) {
        return false;
    }
    else {
        return false;
    }
}

@Override
public int hashCode() {
    final HashCodeBuilder hcb = new HashCodeBuilder( 17, 37 );
    if ( id == null ) {
        while (getOptions().iterator().hasNext())
            hcb.append( getOptions().iterator().next() );
    }
    else {
        hcb.append( id );
    }
    hcb.append( options );
    return hcb.toHashCode();
}

【问题讨论】:

    标签: java postgresql hibernate jpa transient


    【解决方案1】:

    所以答案一直都很琐碎。

    为了克服这个问题,唯一应该做的就是将容器:Set&lt;OptionEntity&gt; 更改为 List&lt;OptionEntity&gt;

    希望这不会产生一些难以解决的错误,但如果可以 - 请添加评论。

    因为在我的情况下,唯一性不是严格的要求,所以最终是这样的:

    投票实体:

    @Table(name = "\"poll\"")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Entity
    @Builder
    public class PollEntity {
    
        @Transient
        public OptionEntity addOption(OptionEntity pollOptionEntity) {
            options.add(pollOptionEntity);
            pollOptionEntity.setPoll(this);
            return pollOptionEntity;
        }
    
        @Transient
        public OptionEntity dropOption(OptionEntity pollOptionEntity) {
            options.remove(pollOptionEntity);
            pollOptionEntity.setPoll(null);
            return pollOptionEntity;
        }
    
        @Id
        @Column(name = "id")
        private UUID id;
        @Column(name = "status")
        @Enumerated(EnumType.STRING)
        @NotNull
        private Status status;
        @Column(name = "author")
        @UUIDv4
        private UUID author;
        @Column(name = "poll_question")
        @Size(max = 1000)
        private String pollQuestion;
        @OneToMany(fetch = FetchType.EAGER, mappedBy = "poll", cascade = CascadeType.MERGE)
        @Builder.Default
        @Valid
        private List<OptionEntity> options = new ArrayList<>();
    }
    

    【讨论】:

      猜你喜欢
      • 2021-07-29
      • 2020-08-16
      • 2017-09-27
      • 1970-01-01
      • 1970-01-01
      • 2012-09-11
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多