2013-11-10 2 views
4

Мне нужно сопоставить имена верблюжьих имен с именами, выделенными яркими символами, в моем текущем проекте, который использует EclipseLink из-за исторических причин. Я знаю, что мы можем индивидуально настраивать сопоставление имен в JPA, но у нас есть длинный список имен верблюжьих дел, которые нужно изменить, поэтому мы хотим избежать такого рода кодов шаблонов, если это возможно.Настроить сопоставление имени поля JPA с помощью EclipseLink

Я хочу достичь следующего. Предположим, у нас есть класс сущностей, как показано ниже:

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

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

Я хочу, чтобы этот класс карты в таблицу с именем «foo_bar» и столбцы «Идентификация» и «date_created». Обратите внимание, что все имена в базе данных находятся в нижнем регистре.

Я googled вокруг и нашел решение для изменения имен таблиц. Однако я не могу понять, как изменить имена полей в классе сущностей.

Ниже приведена моя настройка сопоставления имен, где метод updateFieldNameMappings() не отображает fieldName до field_name, чего я хочу достичь. Проблема сводится к тому, как получить имя поля, как в определении класса. Итак, как мне это сделать в 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)) внутри метода фактически не изменяет сопоставление имени поля, что меня действительно смущает.

редактировать 11/11/13 Я забыл, чтобы понять, что я имел eclipselink.session.customizer включен в persistence.xml. А именно, у меня есть строка, как показано ниже в persistence.xml:

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

Когда ты скажите, что это не дает то, что вы хотите, что именно вы имеете в виду? – JamesB

+0

@JamesB: Спасибо за вопрос. Я обновил свой пост. Надеюсь, теперь это ясно. – JBT

+0

setFieldName должен создать объект DatabaseField из переданной строки, поэтому проверьте, что getFieldName возвращает то, что вы ожидаете после вызова. Вы можете видеть, когда вызывается вызов? Поскольку он работает только с прямыми сопоставлениями полей (базовые отображения JPA), любые другие поля, определенные в других отображениях, будут исключены. – Chris

ответ

6

Вместо

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

попробовать:

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

Это делает трюк для меня под EclipseLink 2.5.0

+0

@@ publysher: Большое вам спасибо! Вы просто сделали мой день. – JBT

+0

Не могли бы вы взглянуть на этот вопрос http://stackoverflow.com/questions/37226244/jpa-set-column-name-for-joincolumnname-at-runtime –

1

Я думаю, вы пропустили добавление следующую строку в persistence.xml сказать EclipseLink использовать свой собственный SessionCustomizer

<property name="eclipselink.session.customizer" value="your.company.package.name.JpaNameMappingCustomizer"/> 

См

http://www.eclipse.org/eclipselink/documentation/2.5/dbws/creating_dbws_services002.htm

http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/p_session_customizer.htm#CHDFBIEI

+0

Спасибо за ответ. Тем не менее, у меня есть эта строка в моем persistence.xml. – JBT

4

Может быть, вы могли бы использовать свой сеанс настройщик. Он преобразует имена таблиц и имена полей в регистр Camel. Он поддерживает наследование и внедряет объекты. Я тестировал 2 года, и у меня не было никаких проблем или побочных эффектов. Наслаждайся этим!

import java.sql.SQLException; 
import java.util.Locale; 
import java.util.Vector; 
import org.eclipse.persistence.config.SessionCustomizer; 
import org.eclipse.persistence.descriptors.ClassDescriptor; 
import org.eclipse.persistence.internal.helper.DatabaseField; 
import org.eclipse.persistence.mappings.DatabaseMapping; 
import org.eclipse.persistence.sessions.Session; 
import org.eclipse.persistence.tools.schemaframework.IndexDefinition; 

public class CamelNamingStrategy implements SessionCustomizer { 
    public static String unqualify(final String qualifiedName) { 
     int loc = qualifiedName.lastIndexOf("."); 
     return loc < 0 ? qualifiedName : qualifiedName.substring(qualifiedName.lastIndexOf(".") + 1); 
    } 

    @Override 
    public void customize(final Session session) throws SQLException { 
     for (ClassDescriptor descriptor : session.getDescriptors().values()) { 
      if (!descriptor.getTables().isEmpty()) { 
       // Take table name from @Table if exists 
       String tableName = null; 
       if (descriptor.getAlias().equalsIgnoreCase(descriptor.getTableName())) { 
        tableName = unqualify(descriptor.getJavaClassName()); 
       } else { 
        tableName = descriptor.getTableName(); 
       } 
       tableName = camelCaseToUnderscore(tableName); 
       descriptor.setTableName(tableName); 
       for (IndexDefinition index : descriptor.getTables().get(0).getIndexes()) { 
        index.setTargetTable(tableName); 
       } 
       Vector<DatabaseMapping> mappings = descriptor.getMappings(); 
       camelCaseToUnderscore(mappings); 
      } else if (descriptor.isAggregateDescriptor() || descriptor.isChildDescriptor()) { 
       camelCaseToUnderscore(descriptor.getMappings()); 
      } 
     } 
    } 

    private void camelCaseToUnderscore(Vector<DatabaseMapping> mappings) { 
     for (DatabaseMapping mapping : mappings) { 
      DatabaseField field = mapping.getField(); 
      if (mapping.isDirectToFieldMapping() && !mapping.isPrimaryKeyMapping()) { 
       String attributeName = mapping.getAttributeName(); 
       String underScoredFieldName = camelCaseToUnderscore(attributeName); 
       field.setName(underScoredFieldName); 
      } 
     } 
    } 

    private String camelCaseToUnderscore(final String name) { 
     StringBuffer buf = new StringBuffer(name.replace('.', '_')); 
     for (int i = 1; i < buf.length() - 1; i++) { 
      if (Character.isLowerCase(buf.charAt(i - 1)) && Character.isUpperCase(buf.charAt(i)) 
        && Character.isLowerCase(buf.charAt(i + 1))) { 
       buf.insert(i++, '_'); 
      } 
     } 
     return buf.toString().toLowerCase(Locale.ENGLISH); 
    } 
} 
+0

Не могли бы вы взглянуть на этот вопрос - http: // stackoverflow.com/questions/37226244/jpa-set-column-name-for-joincolumnname-at-runtime –

0

В случае, если вы хотите провести различие между не-аннотированными элементами и аннотированными элементами с использованием @column аннотаций, то я нашел очень красивый пример этого делать:

public class CamelCaseSessionCustomizer implements SessionCustomizer { 

@Override 
public void customize(Session session) throws SQLException { 
    for (ClassDescriptor descriptor : session.getDescriptors().values()) { 
     // Only change the table name for non-embedable entities with no 
     // @Table already 
     if (!descriptor.getTables().isEmpty() && descriptor.getAlias().equalsIgnoreCase(descriptor.getTableName())) { 
      String tableName = addUnderscores(descriptor.getTableName()); 
      descriptor.setTableName(tableName); 
      for (IndexDefinition index : descriptor.getTables().get(0).getIndexes()) { 
       index.setTargetTable(tableName); 
      } 
     } 
     for (DatabaseMapping mapping : descriptor.getMappings()) { 
      // Only change the column name for non-embedable entities with 
      // no @Column already 

      if (mapping instanceof AggregateObjectMapping) { 
       for (Association association : ((AggregateObjectMapping) mapping).getAggregateToSourceFieldAssociations()) { 
        DatabaseField field = (DatabaseField) association.getValue(); 
        field.setName(addUnderscores(field.getName())); 

        for (DatabaseMapping attrMapping : session.getDescriptor(((AggregateObjectMapping) mapping).getReferenceClass()).getMappings()) { 
         if (attrMapping.getAttributeName().equalsIgnoreCase((String) association.getKey())) { 
          ((AggregateObjectMapping) mapping).addFieldTranslation(field, addUnderscores(attrMapping.getAttributeName())); 
          ((AggregateObjectMapping) mapping).getAggregateToSourceFields().remove(association.getKey()); 
          break; 
         } 
        } 
       } 
      } else if (mapping instanceof ObjectReferenceMapping) { 
       for (DatabaseField foreignKey : ((ObjectReferenceMapping) mapping).getForeignKeyFields()) { 
        foreignKey.setName(addUnderscores(foreignKey.getName())); 
       } 
      } else if (mapping instanceof DirectMapMapping) { 
       for (DatabaseField referenceKey : ((DirectMapMapping) mapping).getReferenceKeyFields()) { 
        referenceKey.setName(addUnderscores(referenceKey.getName())); 
       } 
       for (DatabaseField sourceKey : ((DirectMapMapping) mapping).getSourceKeyFields()) { 
        sourceKey.setName(addUnderscores(sourceKey.getName())); 
       } 
      } else { 
       DatabaseField field = mapping.getField(); 
       if (field != null && !mapping.getAttributeName().isEmpty() && field.getName().equalsIgnoreCase(mapping.getAttributeName())) { 
        field.setName(addUnderscores(mapping.getAttributeName())); 
       } 
      } 
     } 
    } 
} 

private static String addUnderscores(String name) { 
    if (name.equalsIgnoreCase("begintime")) { 
     System.err.println(); 
    } 
    StringBuffer buf = new StringBuffer(name.replace('.', '_')); 
    for (int i = 1; i < buf.length() - 1; i++) { 
     if (Character.isLowerCase(buf.charAt(i - 1)) && Character.isUpperCase(buf.charAt(i)) && Character.isLowerCase(buf.charAt(i + 1))) { 
      buf.insert(i++, '_'); 
     } 
    } 
    return buf.toString().toLowerCase(); 
} 

} 

От https://gist.github.com/ganeshs/c0deb77ffae33dee4555

Смежные вопросы