修剪JPA中的字符串字段

jcr*_*une 32 java jpa

我有一个db表,其数据类型为char(20).我不允许将其更改为varchar.

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

我看不到任何简单的方法来做到这一点.(注释会晃动!).目前我只是从我的getter()返回一个修剪过的值,但这感觉就像一个kludge.

谷歌搜索没有提供任何帮助.有任何想法吗?

Sea*_*oyd 25

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

@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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Trim {}
Run Code Online (Sandbox Code Playgroud)

倾听者

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

<persistence-unit ..>
    <!-- ... -->
    <default-entity-listeners>
      com.somepackage.TrimListener
      and.maybe.SomeOtherListener
    </default-entity-listeners>
</persistence-unit>
Run Code Online (Sandbox Code Playgroud)

 

  • 或者在实体上使用@EntityListeners(YourListener.class)注释 (2认同)

pat*_*ckd 16

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

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


jfa*_*ior 10

这是一个老问题,但对我来说得到答案非常有用。就我而言,最简单的方法是创建一个简单的“javax.persistence.Converter”,如下所示:

@Converter
public class StringTrimConverter implements AttributeConverter<String, String> {

    @Override
    public String convertToDatabaseColumn(String attribute) {
        return attribute;
    }

    @Override
    public String convertToEntityAttribute(String dbData) {
        return dbData.trim();
    }

}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

@Entity
@Table(name = "ViewAddress")
public class PostalAddress extends DbObject { 
    @Convert(converter = StringTrimConverter.class)
    private String street;
    @Convert(converter = StringTrimConverter.class)
    private String number;
    (...)
Run Code Online (Sandbox Code Playgroud)

它工作得很好。