How to map class fields with names other than database columns?

Asked

Viewed 215 times

1

I’m using IDE Intellij. I have the following model:

@Entity(name = "carro")
@Data
public class Carro {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String nome;
    private String tipo;
    private String descricao;
    private String urlFoto;
    private String urlVideo;
    private String latitude;
    private String longitude;
}

I noticed that JPA does not recognize in the standard form, for example:

public class Carro {

When adding the annotation @Entity I’d like him to understand that class Carro would be the table carro in the database

To function properly I had to add this way on @Entity

@Entity(name = "carro")

Just like with the columns urlFoto for example, when performing the query Hibernate gave error saying that the field urlFoto does not exist, that is, he did not convert to url_foto database. But when using H2, it ran normally, ie, recognized and made the conversion to the database format

When mysql

I’ll always have to use the note @Column?? or

I have to make some additional configuration?

[EDIT] In my file application.properties is like this:

# MySQL
spring.datasource.url=jdbc:mysql://localhost:3307/carros?useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

#SQL.
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.initialization-mode=always
spring.jpa.hibernate.ddl-auto=none

# logging
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.level.org.hibernate.SQL=debug

2 answers

2

You can use the annotation @Column(name = "url_foto") above the field urlFoto.

We use this annotation when the column name in the database is different from the class field name.

  • That’s right... when I use the H2 database, it alone does this conversion for me

2


The behavior you expect can be implemented through a ImplicitNamingStrategy or PhysicalNamingStrategy. That’s the mechanism that determines how class and field names will be translated into tables and columns.

I believe that a PhysicalNamingStrategy that already does what you need is the one that comes as default in Spring (github link):

import java.util.Locale;

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

/**
 * Hibernate {@link PhysicalNamingStrategy} that follows Spring recommended naming
 * conventions.
 *
 * @author Phillip Webb
 * @author Madhura Bhave
 * @since 1.4.0
 */
public class SpringPhysicalNamingStrategy implements PhysicalNamingStrategy {

    @Override
    public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
        return apply(name, jdbcEnvironment);
    }

    @Override
    public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) {
        return apply(name, jdbcEnvironment);
    }

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
        return apply(name, jdbcEnvironment);
    }

    @Override
    public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) {
        return apply(name, jdbcEnvironment);
    }

    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
        return apply(name, jdbcEnvironment);
    }

    private Identifier apply(Identifier name, JdbcEnvironment jdbcEnvironment) {
        if (name == null) {
            return null;
        }
        StringBuilder builder = new StringBuilder(name.getText().replace('.', '_'));
        for (int i = 1; i < builder.length() - 1; i++) {
            if (isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
                builder.insert(i++, '_');
            }
        }
        return getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
    }

    /**
     * Get an identifier for the specified details. By default this method will return an
     * identifier with the name adapted based on the result of
     * {@link #isCaseInsensitive(JdbcEnvironment)}
     * @param name the name of the identifier
     * @param quoted if the identifier is quoted
     * @param jdbcEnvironment the JDBC environment
     * @return an identifier instance
     */
    protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
        if (isCaseInsensitive(jdbcEnvironment)) {
            name = name.toLowerCase(Locale.ROOT);
        }
        return new Identifier(name, quoted);
    }

    /**
     * Specify whether the database is case sensitive.
     * @param jdbcEnvironment the JDBC environment which can be used to determine case
     * @return true if the database is case insensitive sensitivity
     */
    protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
        return true;
    }

    private boolean isUnderscoreRequired(char before, char current, char after) {
        return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
    }

}

In a Spring Boot project just use the configuration:

spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
  • How I care about Spring?

  • When I put this in the file application.properties: spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategy tive o seguinte erro: Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.boot.registry.selector.spi.StrategySelectionException: Could not instantiate named Strategy class [org.hibernate.boot.model.naming.Physicalnamingstrategy]

  • It used to look like this: #spring.jpa.Hibernate.naming.Physical-Strategy=org.hibernate.boot.model.naming.Physicalnamingstrategystandardimpl

  • 1

    @adventistaam If you are already in a Spring Boot project, and depending on the version, just use spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

  • 1

    That’s right... it worked... If you can add in the answer, I thank you

Browser other questions tagged

You are not signed in. Login or sign up in order to post.