使用EclipseLink自定义JPA字段名称映射 [英] Customize JPA field name mapping using EclipseLink

查看:200
本文介绍了使用EclipseLink自定义JPA字段名称映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于历史原因,我需要将当前项目中使用EclipseLink的驼峰分隔名称映射到下划线名称。我知道我们可以在JPA中单独定制名称映射,但我们有一长串的驼峰名称要更改,所以我们想要尽可能避免使用那种样板代码。

I need to map camel-case names to underscore-separated names in my current project, which uses EclipseLink, due to historical reasons. I know we can customize name mapping individually in JPA, but we have a long list of camel-case names to change, so we want to avoid that kind of boilerplate codes if all possible.

我想要实现的目标如下。假设我们有一个实体类如下:

What I want to achieve is as follows. Suppose we have an entity class as below:

@Entity
public class FooBar {
    @Id @GeneratedValue
    private Long id;

    @Temporal( TemporalType.TIMESTAMP )
    private Date dateCreated;
}

我希望这个类映射到名为foo_bar的表和列 id和date_created。请注意,数据库中的所有名称都是小写的。

I want this class maps to a table with name "foo_bar" and columns "id" and "date_created". Note that all names in database are in lower case.

我搜索了一下,找到了更改表名的解决方案。但是,我无法弄清楚如何在实体类中更改字段名称。

I googled around, and found a solution for changing table names. However, I can't figure out how to change field names in an entity class.

下面是我的名字映射定制器,其中方法 updateFieldNameMappings()未映射 fieldName field_name ,这是我想要实现的。问题归结为如何在类定义中获取字段名称。那么,我如何在EclipseLink中做到这一点?

Below is my name-mapping customizer, where the method updateFieldNameMappings() is not mapping fieldName to field_name, which is what I want to achieve. The problem boils down to how to get the field name as in the class definition. So, how do I do that in EclipseLink?

public class JpaNameMappingCustomizer implements SessionCustomizer {

    @Override
    public void customize( Session session ) throws Exception {
        Map<Class, ClassDescriptor> descs = session.getDescriptors();
        Collection<ClassDescriptor> descriptors = descs.values();

        // This code assumes single table per descriptor!
        for (ClassDescriptor desc : descriptors) {
            updateTableNameMapping( desc );
            updateFieldNameMapping( desc );
        }
    }

    private void updateTableNameMapping ( ClassDescriptor desc ) {
        Class clazz = desc.getJavaClass();
        String tableName = camelCaseToUnderscore( clazz.getSimpleName() );
        desc.setTableName( tableName );
    }

    private void updateFieldNameMapping ( ClassDescriptor desc ) {
        // build name maps
        Field[] fields = desc.getJavaClass().getDeclaredFields();
        String tableName = desc.getTableName();
        Map<String,String> nameMap = new HashMap<>();
        String prefix = tableName + ".";
        for( Field field : fields ) {
            String name = field.getName();
            String key = prefix + name.toUpperCase();
            String value = prefix + camelCaseToUnderscore( name );
            nameMap.put( key, value );
        }

        for (DatabaseMapping mapping : desc.getMappings()) {
            if (mapping.isDirectToFieldMapping()) {
                DirectToFieldMapping directMapping = (DirectToFieldMapping) mapping;
                String oldFieldName = directMapping.getFieldName(); // format: table_name.FIELD
                directMapping.setFieldName( nameMap.get( oldFieldName ) );
            }
        }
    }

    private String camelCaseToUnderscore( String camelCase ) {
        return camelCase.trim().replaceAll("(?<!^)[A-Z](?!$)", "_$0").toLowerCase();
    }
}

编辑11/10/13
我做了一些黑客攻击并改变了定制器。 updateFieldNameMapping()仍然无法解决问题。在我看来,该方法中的语句 directMapping.setFieldName(nameMap.get(oldFieldName))实际上并没有改变字段名称映射,这实在让我感到困惑。

edit 11/10/13 I did some hacking and changed the customizer. The updateFieldNameMapping() still doesn't do the trick. It seems to me that this statement directMapping.setFieldName( nameMap.get( oldFieldName ) ) inside the method doesn't actually change the field name mapping, which really confuses me.

编辑11/11/13
我忘了说清楚我有 eclipselink.session .customizer persistence.xml 中启用。也就是说,我在 persistence.xml 中有如下所示的行:

edit 11/11/13 I forgot to make it clear that I had the eclipselink.session.customizer enabled in the persistence.xml. Namely, I have a line like below in the persistence.xml:

<property name="eclipselink.session.customizer" value="pkg.JpaNameMappingCustomizer"/>


推荐答案

而不是

directMapping.setFieldName(nameMap.get(oldFieldName ));

尝试:

directMapping.getField().resetQualifiedName(nameMap.get(oldFieldName));

这在EclipseLink 2.5.0下为我提供了诀窍

This does the trick for me under EclipseLink 2.5.0

这篇关于使用EclipseLink自定义JPA字段名称映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆