Aharon Bar-El
Aharon Bar-El

Reputation: 155

Spring boot + hibernate - entity is not mapped + best way to configuration

I'm trying to learn spring-boot basic annotation configuration with hibernate, to make myself a template that will always work.

I'm using spring-boot latest release version 1.51 on STS (spring tool suite) 3.8.3.

Here is my main:

@SpringBootApplication
@EnableAutoConfiguration
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Now, I know that @SpringBootApplication automatically comes with @componetScan, so I didn't add it.

My configuration class:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "someEntityManagerFactory", transactionManagerRef = "someTransactionManager", basePackages = {
        "com.example.*" })
@EntityScan(basePackages = "com.demo.models")
@ConfigurationProperties(prefix = "mysql.datasource")
public class DataBaseConfig {

    @Autowired
    private Environment env;

    @Bean
    public DataSource someDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("mysql.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("mysql.datasource.url"));
        dataSource.setUsername(env.getProperty("mysql.datasource.username"));
        dataSource.setPassword(env.getProperty("mysql.datasource.password"));
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean someEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(someDataSource());
        em.setPackagesToScan(new String[] { "org.openlegacy.analytics.models" });
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;
    }

    @Bean
    public PlatformTransactionManager someTransactionManager() {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(someEntityManagerFactory().getObject());
        tm.setDataSource(someDataSource());
        return tm;
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
        properties.setProperty("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect"));
        properties.setProperty("spring.jpa.show-sql", env.getProperty("spring.jpa.show-sql"));
        properties.setProperty("spring.jpa.hibernate.naming.physical-strategy",
                env.getProperty("spring.jpa.hibernate.naming.physical-strategy"));
        return properties;
    }

}

My controller class:

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserRepository userRipository;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public List<User> getItems() {
        return userRipository.getUsers();
    }

    @RequestMapping(value = "/message", method = RequestMethod.GET)
    public String getMessage() {
        return userRipository.getMessage();
    }

}

My repository class:

@Transactional
@Repository
public class UserRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @SuppressWarnings("unchecked")
    public List<User> getUsers() {
        return entityManager.createQuery("select u from User u").getResultList();
    }

    public String getMessage() {
        return "hello";
    }
}

My entity class:

@Entity(name = "user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "password")
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

and my properties file:

# DataSource settings: set here your own configurations for the database connection.
mysql.datasource.username=openlegacy
mysql.datasource.password=openlegacy
mysql.datasource.driver-class-name=com.mysql.jdbc.Driver
mysql.datasource.url=jdbc:mysql://localhost:3306/olbank
spring.jpa.database= MYSQL

spring.data.jpa.repositories.enabled=true
#spring.jpa.database-platform=org.hibernate.dialect.MYSQL5Dialect

# Show or not log for each sql query
spring.jpa.show-sql = true

# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
#spring.jpa.hibernate.naming.strategy= org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.hibernate.naming.physical-strategy= org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

and when I'm tying to retrieve data from the user table, I get this error:

org.hibernate.hql.internal.ast.QuerySyntaxException: User is not mapped...

My questions are:

  1. why am I getting this error? I know that user is mapped by the class name, and that's what I'm doing

  2. is this the best way to configure hibernate with spring-boot? It's important for me to write code by the best practices.

Please give a detailed answer so I can learn from it.

Any other information that can be useful is welcome :)

Thanks.

Upvotes: 3

Views: 37662

Answers (7)

Eduardo Vila&#231;a
Eduardo Vila&#231;a

Reputation: 7

In my case, with the entity name was not working, so i added instead entity.class.getName();

Upvotes: 0

Shubham
Shubham

Reputation: 39

If you are using JPQL then don't forget to add nativeQuery=true after your JPQL query in repository interface.

Example:-

@Query(value="SELECT ID, NAME FROM USER", nativeQuery=true)
Object getUser();

Upvotes: 1

Ahmad Alhaj-Karim
Ahmad Alhaj-Karim

Reputation: 194

In my case, i had to add the name for the Entity. @Entity(name = "users")

@Entity(name = "users")
@Table(name = "users")
public class User  implements Serializable{
}

UPDATE If you leave the entity without name and write the class name, it also should work .

@Entity
@Table
public class User  implements Serializable{
}

and then

@query("select u from User u")

Upvotes: 1

nokieng
nokieng

Reputation: 2126

Entity is not mapped (JPA Native Query)

With Spring boot JPA, by default, each query will refer to the column or the variable that is defined in an @Entity class that mapped to each column in the database.

However, it is possible to use a native query or raw query

public interface UserInfoRepository extends CrudRepository<UserModel, String>
    @Query("SELECT ID, NAME FROM USER", nativeQuery = true)
    Optional<List<UserModel>> findSomething();
}

The columns ID and Name are the column name according to the database (Native Query)

Example of using EntityManager

Query query = em.createNativeQuery("SELECT ID, NAME FROM USER")

My suggestion on The Best way to configure (Oracle)

  1. Config dataSource in application.yml
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    username: username
    password: pass
    hikari:
      idle-timeout: 1000 
      maximum-pool-size: 10
      minimum-idle: 2
      pool-name: pool-name
      jdbc-url: jdbc:oracle:thin:@localhost:1521:INSTANCE
      driver-class-name: oracle.jdbc.OracleDriver
  1. Create an @Entity class using lombok or without lombok (manually create getter, setter functions)
@Data
@NoArgsConstructor
@EntityScan
@Entity(name = "USER")
public class UserInfoModel {

    @Id
    @Column(name = "USERID")
    private long userId;
    @Column(name = "NAME")
    private String name;
    @Column(name = "DEPT")
    private String dept;
}
  1. Create an interface CRUD repository
public interface UserInfoRepository extends CrudRepository<UserInfoModel, Long> {
}
  1. Create an @Service class to wrapp around a repository as a business layer and do your logic here
@Service
public class UserServiceImpl implements UserService {

   @Autowired
   private UserInfoRepository userInfoRepo;

   @Override
   public List<UserInfoModel> getUserInfo(long userId) throws Exception {
       Optional<List<UserInfoModel>> info = userInfoRepo.findById(userId);
       if (!info.isEmpty() && info.get().size() > 0) {
           return info.get();
       }
       return null;
   }
}

  1. Finally, call the @Service class in your controller

@RestController
@RequestMapping("/webint")
public class UserController {

    @Autowired
    private UserService userService;
}

Hope, this guides someone having trouble like me a few weeks ago

Upvotes: 0

j&#233;r&#233;my
j&#233;r&#233;my

Reputation: 16

Did you try bellow for entity:

@Entity
@Table(name = "user")
public class User implements Serializable {
}

Upvotes: 0

Imad ALILAT
Imad ALILAT

Reputation: 92

Spring JPA is case sensitive, so be sure you wrote the exact package URL and the correct class name.

Upvotes: 2

M. Rizzo
M. Rizzo

Reputation: 2261

Ok. You have a few things that need to be addressed in your overall configuration. You currently are providing an alias to your Entity User

@Entity(name = "user")

That is fine but if you are going to provide a name to your Entity then that is how you need to reference it in JPQL so, "select u from User u" would need to become

select u from user u

I might just suggest getting rid of your name qualifier and leave your query as "select u from User u".

Then secondly you do have some issues with package references:

  1. In your @EnableJpaRepositories annotation change your basePackages to reference the base of your actual repository package, guessing "com.demo.repository". Get rid of the wildcard reference.
  2. In your someEntityManagerFactory() method you are setting the basePackage to (something I imagine is incorrect) "org.openlegacy.analytics.models". You indicated your entity(s) is under "com.demo.models". So you should change that setter to

    em.setPackagesToScan(new String[] { "com.demo.models" });
    

That should do the trick.

Upvotes: 18

Related Questions