尝试使用Spring Data JPA + Lombok级联持久性时,“非空属性引用一个瞬态值”

问题描述

我试图从父级实体中级联孩子的持久性,但是这种关系没有得到维持,我不知道为什么。

我尝试将级联放在另一侧或两侧,并使用CascadeType.PERSIST代替CascadeType.ALL(如某些文章所建议的),但是没有运气。

谢谢您的任何帮助。

@DataJpaTest
public class TaskEntityRepositoryIntegrationTests {
    @Inject
    private TaskEntityRepository taskEntityRepository;

    @Test
    void testRelationshipPersistence() {
        TaskDao taskDao = TaskDao.builder()
                .title("Title")
                .build();

        TagDao tagDao = TagDao.builder()
                .tag("Tag")
                .task(taskDao)
                .build();

        taskDao = taskDao.toBuilder()
                .tag(tagDao)
                .build();

        TaskDao result = this.taskEntityRepository.save(taskDao);

        assertEquals(tagDao,result.getTags().iterator().next());
    }
}
2020-09-16 11:16:57.317  INFO 11406 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@5038d0b5 testClass = TaskEntityRepositoryIntegrationTests,testInstance = TaskEntityRepositoryIntegrationTests@1169afe1,testMethod = testRelationshipPersistence@TaskEntityRepositoryIntegrationTests,testException = [null],mergedContextConfiguration = [MergedContextConfiguration@32115b28 testClass = TaskEntityRepositoryIntegrationTests,locations = '{}',classes = '{class TasksApplication}',contextInitializerClasses = '[]',activeProfiles = '{}',propertySourceLocations = '{}',propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}',contextCustomizers = set[[ImportsContextCustomizer@2ad48653 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration,org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]],org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@618425b5,org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@f5acb9d,org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0,org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@54bff557,org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0,org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@8b05feb1,org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@59505b48,org.springframework.boot.test.context.SpringBootTestArgs@1],contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader',parent = [null]],attributes = map[[empty]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@46a0ef6f]; rollback [true]
Hibernate: insert into tasks (id,title) values (null,?)
2020-09-16 11:16:57.868  WARN 11406 --- [           main] o.h.a.i.UnresolvedEntityInsertActions    : HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
    Unsaved transient entity: ([TaskDao#<null>])
    Dependent entities: ([[TagDao#<null>]])
    Non-nullable association(s): ([TagDao.task])
2020-09-16 11:16:57.883  INFO 11406 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@5038d0b5 testClass = TaskEntityRepositoryIntegrationTests,testException = org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : TagDao.task -> TaskDao; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : TagDao.task -> TaskDao,attributes = map[[empty]]]


org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : TagDao.task -> TaskDao; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : TagDao.task -> TaskDao
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name="tasks")
@Builder(toBuilder = true)
public class TaskDao implements Serializable {
    private static final long serialVersionUID = -1128682442577176872L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Column
    String title;

    @Singular
    @OneToMany(mappedBy= "task",cascade = CascadeType.ALL)
    Collection<TagDao> tags;
}
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name="tags")
@Builder(toBuilder = true)
public class TagDao implements Serializable {
    private static final long serialVersionUID = -1128682442577176872L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Column
    String tag;

    @ManyToOne(optional = false)
    TaskDao task;
}
@Repository
public interface TaskEntityRepository extends JpaRepository<TaskDao,Long> {
}

如果我删除这些行,则保存成功,但是断言失败,因为父级关系为空

taskDao = taskDao.toBuilder()
    .tag(tagDao)
    .build();
2020-09-16 12:09:46.134  INFO 12078 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@18f8cd79 testClass = TaskEntityRepositoryIntegrationTests,testInstance = TaskEntityRepositoryIntegrationTests@33f676f6,mergedContextConfiguration = [MergedContextConfiguration@3e2055d6 testClass = TaskEntityRepositoryIntegrationTests,contextCustomizers = set[[ImportsContextCustomizer@50029372 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5acf93bb,org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@614ca7df,org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@6392827e,org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@2dc54ad4,attributes = map[[empty]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@787a4519]; rollback [true]
Hibernate: insert into tasks (id,?)
Hibernate: select taskdao0_.id as id1_3_,taskdao0_.title as title7_3_ from tasks taskdao0_
2020-09-16 12:09:46.828  INFO 12078 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@18f8cd79 testClass = TaskEntityRepositoryIntegrationTests,testException = java.util.NoSuchElementException,attributes = map[[empty]]]


java.util.NoSuchElementException
    at java.base/java.util.Collections$EmptyIterator.next(Collections.java:4277)
    at org.hibernate.collection.internal.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:883)
    at TaskEntityRepositoryIntegrationTests.testRelationshipPersistence(TaskEntityRepositoryIntegrationTests.java:98)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)