【问题标题】:How to extend Entity from AbstractAuditingEntity on Jhipster generated app?如何在 Jhipster 生成的应用程序上从 AbstractAuditingEntity 扩展实体?
【发布时间】:2015-08-26 16:54:50
【问题描述】:

我已经使用命令yo jhipster:entity MyEntity 生成了一个实体(我使用的是 generator-jhipster@2.19.0)

以及以下选项

{
    "relationships": [],
    "fields": [
        {
            "fieldId": 1,
            "fieldName": "title",
            "fieldType": "String"
        }
    ],
    "changelogDate": "20150826154353",
    "dto": "no",
    "pagination": "no"
}

我已在 liquibase 更改日志文件中添加了可审核的列

<changeSet id="20150826154353" author="jhipster">
    <createSequence sequenceName="SEQ_MYENTITY" startValue="1000" incrementBy="1"/>
    <createTable tableName="MYENTITY">
        <column name="id" type="bigint" autoIncrement="${autoIncrement}" defaultValueComputed="SEQ_MYENTITY.NEXTVAL">
            <constraints primaryKey="true" nullable="false"/>
        </column>
        <column name="title" type="varchar(255)"/>

        <!--auditable columns-->
        <column name="created_by" type="varchar(50)">
            <constraints nullable="false"/>
        </column>
        <column name="created_date" type="timestamp" defaultValueDate="${now}">
            <constraints nullable="false"/>
        </column>
        <column name="last_modified_by" type="varchar(50)"/>
        <column name="last_modified_date" type="timestamp"/>
    </createTable>

</changeSet>

并修改 MyEntity 类以扩展 AbstractAuditingEntity

@Entity
@Table(name = "MYENTITY")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class MyEntity extends AbstractAuditingEntity implements Serializable {

然后运行mvn test 并得到以下异常

[DEBUG] com.example.web.rest.MyEntityResource - REST request to update MyEntity : MyEntity{id=2, title='UPDATED_TEXT'}

javax.validation.ConstraintViolationException: Validation failed for classes [com.example.domain.MyEntity] during update time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=createdBy, rootBeanClass=class com.example.domain.MyEntity, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:160)
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreUpdate(BeanValidationEventListener.java:103)
    at org.hibernate.action.internal.EntityUpdateAction.preUpdate(EntityUpdateAction.java:257)
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:134)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:67)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1191)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1257)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573)
    at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:449)
    at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:67)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:318)

这是失败的测试

@Test
    @Transactional
    public void updateMyEntity() throws Exception {
        // Initialize the database
        myEntityRepository.saveAndFlush(myEntity);

        int databaseSizeBeforeUpdate = myEntityRepository.findAll().size();

        // Update the myEntity
        myEntity.setTitle(UPDATED_TITLE);


        restMyEntityMockMvc.perform(put("/api/myEntitys")
                .contentType(TestUtil.APPLICATION_JSON_UTF8)
                .content(TestUtil.convertObjectToJsonBytes(myEntity)))
                .andExpect(status().isOk());

        // Validate the MyEntity in the database
        List<MyEntity> myEntitys = myEntityRepository.findAll();
        assertThat(myEntitys).hasSize(databaseSizeBeforeUpdate);
        MyEntity testMyEntity = myEntitys.get(myEntitys.size() - 1);
        assertThat(testMyEntity.getTitle()).isEqualTo(UPDATED_TITLE);
    }

引发异常的行是这样的

List<MyEntity> myEntitys = myEntityRepository.findAll();

我注意到 TestUtil.convertObjectToJsonBytes(myEntity) 方法正在返回没有可审计属性的 JSON 对象表示 - 这是由于 @JsonIgnore 注释而预期的 - 但我认为 mockMVC.perform 更新操作不尊重 updatable = false 属性在 createdBy 字段上设置

@CreatedBy
@NotNull
@Column(name = "created_by", nullable = false, length = 50, updatable = false)
@JsonIgnore
private String createdBy;

如何使实体可审计并通过测试?

【问题讨论】:

  • 我已经检查了这个issue,但问题有点不同
  • 同时我添加了一个解决方法,只需在 restMyEntityMockMvc.perform 之后将 createdBy 属性设置为 'system'

标签: java hibernate spring-mvc testing jhipster


【解决方案1】:

问题在于传输的(序列化)对象不包括可审计的属性(由于@JsonIgnore 注释),这与@NotNull 注释相结合会产生ConstraintViolation。

1.- 一种解决方案是首先检索我们要更新的对象,然后只更新您需要的字段。因此,在我们的示例中,我们需要修改更新方法在 MyEntityResource 类上如下:

/**
 * PUT  /myEntitys -> Updates an existing myEntity.
 */
@RequestMapping(value = "/myEntitys",
    method = RequestMethod.PUT,
    produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public ResponseEntity<MyEntity> update(@RequestBody MyEntity myEntityReceived) throws URISyntaxException {
    log.debug("REST request to update MyEntity : {}", myEntityReceived);
    if (myEntityReceived.getId() == null) {
        return create(myEntityReceived);
    }
    MyEntity myEntity = myEntityRepository.findOne(myEntityReceived.getId());
    myEntity.setTitle(myEntityReceived.getTitle());
    MyEntity result = myEntityRepository.save(myEntity);
    return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert("myEntity", myEntity.getId().toString()))
            .body(result);
}

2.- 另一种解决方案是通过从 AbstractAuditingEntity 中删除所需值上的 @JsonIgnore 注释来包含可审计字段。

创建实体时会产生如下响应

{
"createdBy":"admin",
"createdDate":"2015-08-27T17:40:20Z",
"lastModifiedBy":"admin",
"lastModifiedDate":"2015-08-27T17:40:20Z",
"id":1,
"title":"New Entity"
}

因此,当更新实体时,请求将包含先前生成的值

{
"createdBy":"admin",
"createdDate":"2015-08-27T17:40:20Z",
"lastModifiedBy":"admin",
"lastModifiedDate":"2015-08-27T17:40:20Z",
"id":1,
"title":"New Entity Updated"
}

同样是更新响应,但更新了 lastModified 字段

{
"createdBy":"admin",
"createdDate":"2015-08-27T17:40:20Z",
"lastModifiedBy":"admin",
"lastModifiedDate":"2015-08-27T17:45:12Z",
"id":1,
"title":"New Entity Updated"
}

这两种解决方案都有自己的取舍,因此请选择最适合您的解决方案。

此外,您应该在 generator-jhipster 上查看此 issue,尽管它的标题仅为 DTO 实体,但无论您是否使用它们都是同样的问题。

【讨论】:

    【解决方案2】:

    正如我在一些与 JHipster 相关的问题上发现的(现在找不到该页面,我会参考它)最好和最简单的解决方案(在我看来)是这个包 for applying audit on generated entities .

    它包含您需要的所有内容,它还会更改更改日志文件并在数据库中生成列:created_by、created_date、last_modified_by 和 last_modified_date。

    最好的问候

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-22
      • 2020-03-05
      相关资源
      最近更新 更多