修剪 JPA 中的字符串字段

2022-09-01 03:39:15

我有一个数据库表,其中的列数据类型为char(20)。我不允许将其更改为varchar。

我正在编写一个映射到此表的 JPA 实体。我希望在我的实体类中表示此列的字符串字段始终包含修剪后的值,而不是用数据库中存在的空格填充的20个字符的值。

我看不出有任何简单的方法来做到这一点。(注释会摇滚!目前,我只是从我的 getter() 返回一个修剪过的值,但这感觉就像是一个笨拙。

谷歌搜索对此没有任何帮助。有什么想法吗?


答案 1

或者,您可以使用生命周期注释:

@Entity
public class MyEntity {

    @PostLoad
    protected void repair(){
        if(myStringProperty!=null)myStringProperty=myStringProperty.trim();
    }

    private String myStringProperty;
    public String getMyStringProperty() {
        return myStringProperty;
    }
    public void setMyStringProperty(String myStringProperty) {
        this.myStringProperty = myStringProperty;
    }

}

如果这种情况发生在多个实体上,则可以创建自定义批注并编写专用的 EntityListener。

注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Trim {}

听者

public class TrimListener {

    private final Map<Class<?>, Set<Field>> trimProperties = 
        new HashMap<Class<?>, Set<Field>>();

    @PostLoad
    public void repairAfterLoad(final Object entity) throws Exception {
        for (final Field fieldToTrim : getTrimProperties(entity.getClass())) {
            final String propertyValue = (String) fieldToTrim.get(entity);
            if (propertyValue != null)
                fieldToTrim.set(entity, propertyValue.trim());
        }
    }

    private Set<Field> getTrimProperties(Class<?> entityClass) throws Exception {
        if (Object.class.equals(entityClass))
            return Collections.emptySet();
        Set<Field> propertiesToTrim = trimProperties.get(entityClass);
        if (propertiesToTrim == null) {
            propertiesToTrim = new HashSet<Field>();
            for (final Field field : entityClass.getDeclaredFields()) {
                if (field.getType().equals(String.class)
                    && field.getAnnotation(Trim.class) != null) {
                    field.setAccessible(true);
                    propertiesToTrim.add(field);
                }
            }
            trimProperties.put(entityClass, propertiesToTrim);
        }
        return propertiesToTrim;
    }

}

现在,使用注释所有相关的 String 字段,并将监听器注册为持久性中的默认实体监听器.xml:@Trim

<persistence-unit ..>
    <!-- ... -->
    <default-entity-listeners>
      com.somepackage.TrimListener
      and.maybe.SomeOtherListener
    </default-entity-listeners>
</persistence-unit>

 


答案 2

接受的答案(使用JPA实体侦听器/@Trim注释)是一个危险的答案。对检索到的实体调用 setter 似乎会将该实体标记为脏。当我在根实体级别(使用Spring3 / hibernate)自己尝试时,它触发了对相关实体的大量无关更新,否则这些更新在事务期间不会被修改。这在生产中是一个真正的混乱,追踪它的原因需要时间。

最后,我选择采用更直接的方法,即按需手动修剪每个字段(在自定义实体到域映射器中,或在实体获取器中),类似于Edwin的答案。


推荐