如何在Spring Boot中插入并返回完整对象

时间:2015-05-17 14:59:03

标签: hibernate jpa spring-boot

这个问题类似于this one,但我的问题特别针对Spring Boot的原生CrudRepository和JpaRepository,它们似乎没有refresh()方法。我正在保存一个包含现有子对象的ID的新对象。应用程序是RESTful,插入的数据是来自客户端的JSON。正确插入新记录,但返回值中的子对象仍仅包含ID。 Spring Boot等效于refresh()吗?我是否需要创建可访问EntityManager的自定义存储库?

我应该在插入后使用findOne()来解决问题。子对象仍然不完整。但是,当我在单独的REST调用中选择插入的记录时,该对象与所有子对象一起完成。

代码如下。正如您所看到的,存储库和服务方法非常简单,我没有看到该做什么。刷新看起来像Spring Boot应该自动处理的东西。

注意:SO注释表单正在从CrudRepository中删除参数 返回类型。

Volume.java



    @Entity
    @JsonSerialize(using = VolumeSerializer.class)
    public class Volume implements Protectable {

        public static final int ATTACHED_STATE = 1;
        public static final int DETACHED_STATE = 0;
        public static final int SUSPENDED_STATE = -1;

        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long id;
        private String name;
        @OneToOne
        private VolumeType type;
        private int size;
        @OneToOne
        private UserGroup userGroup;
        @OneToOne
        private Region region;
        @OneToOne
        private State state;
        @OneToOne
        private Status status;
        @OneToOne
        private Alarm alarmStatus;
        private long createdDate;
        @Column(columnDefinition = "bigint default 0")
        private long lastModifiedDate = 0;
        @Column(columnDefinition = "tinyint default 0")
        private boolean monitoringEnabled = false;
        @Column(columnDefinition = "tinyint default 0")
        private boolean encrypted = false;
        @OneToOne
        private Snapshot snapshot;
        @ManyToOne
        private Instance instance;
    /*
    after this there are constructors, a long list of getters for the properties above
    a static Builder class and @PrePersist and @PreUpdate methods
    */
    ...

VolumeRepository.java


    /**
     * For accessing Volume information
     */
    public interface VolumeRepository extends CrudRepository {
       List findByUserGroupId(long groupId);
    }

VolumeService.java



    @Transactional
    public Iterable save(List volumes) {
       return this.repository.save(volumes);
    }

VolumeRouter.java

这是一个@RestController。



    @RequestMapping(value="/volumes", method=RequestMethod.POST)
    public Iterable create(@RequestBody List volumes) {
        return this.service.save(volumes);
    }

application.properties

(ddl-auto设置用于开发)



    # Datasource configuration
    spring.datasource.url=****
    spring.datasource.username=****
    spring.datasource.password=****
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.time-between-eviction-runs-millis=34000
    spring.datasource.min-evictable-idle-time-millis=55000
    spring.datasource.min-idle=0


    # Hibernate settings
    spring.jpa.hibernate.ddl-auto=create-drop
    spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
    spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy

VolumeServiceIT.java

JSON字符串显示客户端所期望的内容 能够发送到服务。 UserGroup对象仅包含 从客户端发送的ID,但它应该是完整的UserGroup 宾语。其他子对象也是如此。



    @Test
    public void createVolume() throws Exception {
        String json = "[{" +
                    "\"name\": \"Test Volume\", " +
                    "\"size\": 24, " +
                    "\"monitoringEnabled\": true, " +
                    "\"encrypted\": true, " +
                    "\"state\": { \"id\": 1 }, " +
                    "\"userGroup\": { \"id\": 1 }, " +
                    "\"region\": { \"id\": 1 }, " +
                    "\"type\": { \"id\": 1 }" +
                "}]";

        mvc.perform(MockMvcRequestBuilders.post("/volumes")
                .principal(token)
                .contentType(MediaType.APPLICATION_JSON)
                .content(json))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].id", is(4)))
                .andExpect(jsonPath("$[0].name", is("Test Volume")))
                .andExpect(jsonPath("$[0].size", is(24)))
                .andExpect(jsonPath("$[0].userGroup.id", is(1)))
                .andExpect(jsonPath("$[0].userGroup.name", is("myGroup")))
                .andExpect(jsonPath("$[0].userGroup.users", isEmptyOrNullString()))
                .andExpect(jsonPath("$[0].type.id", is(1)))
                .andExpect(jsonPath("$[0].type.value", is("SSD")))
                .andExpect(jsonPath("$[0].region.id", is(1)))
                .andExpect(jsonPath("$[0].region.value", is("us-west")))
                .andExpect(jsonPath("$[0].state.id", is(1)))
                .andExpect(jsonPath("$[0].state.value", is("on")))
                .andExpect(jsonPath("$[0].status", isEmptyOrNullString()))
                        //.andExpect(jsonPath("$.createdDate", is(1425240151000L)))
                .andExpect(jsonPath("$[0].monitoringEnabled", is(true)))
                .andExpect(jsonPath("$[0].encrypted", is(true)));
    }

1 个答案:

答案 0 :(得分:2)

在与同事协商后,我将EntityManager注入上面的VolumeService并在卷上调用了刷新。



        @PersistenceContext
        private EntityManager entityManager;

    ...

        @Transactional
        public Iterable save(List volumes) {
            Iterable result = this.repository.save(volumes);

            for (Volume volume : result){
                entityManager.refresh(volume);
            }
            return result;
        }

请注意,虽然我更喜欢这个选项,但我的同事建议获取子对象,将它们添加到新卷,然后保存卷,这显然有效。但是,我不想这样做。