Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Erro ao persistir classes com herança Spring Boot Spring JPA

Ola estou tentando aplicar o CrudRepository nas minhas classes com herança mas esta dando o seguinte erro:

Caused by: org.postgresql.util.PSQLException: ERROR: relation "usuario" does not exist

Segue classes no meu projeto

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="Tipo_usu",discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("usuario")
public class Usuario implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    private String EMail;

    private String Profile;
    private String Nome;

//demais campos omitidos

@Entity
@DiscriminatorValue("aluno")
public class Aluno extends Usuario{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
    @JoinColumn(name="instrutor_EMail")
    private Instrutor instrutor;

@Entity
@DiscriminatorValue("admin")
public class Admin extends Usuario{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

Minha implementacao de Repository


@NoRepositoryBean
public interface UsuarioBaseRepository<T extends Usuario> extends CrudRepository<T, String> {


}

@Transactional
public interface AlunoRepository extends UsuarioBaseRepository<Aluno>, CrudRepository<Aluno, String>{


}

@Transactional
public interface AdminRepository extends UsuarioBaseRepository<Admin>, CrudRepository<Admin, String> {

}

E o Service do aluno

@Service
public class AlunoService {

    @Autowired
    private AlunoRepository repository;


    public void cadastrar(Aluno aluno) {
        repository.save(aluno);
    }

    public Iterable<Aluno> listar(){
        return repository.findAll();
    }

    public Optional<Aluno> detalhe(String email) {
        return repository.findById(email);
    }
}

Desde ja muito obrigado pela ajuda!!

5 respostas

Ola novamente, consegui encontrar o erro, era na criação do bd, o metodo de propeerties que eu criei nao esta sendo lido pelo spring. O que me leva a seguinte pergunta: Como eu devo colocar esse método no contexto da aplicação do Spring Boot:

public class AcademiaOnlineApplication {

    public static void main(String[] args) {
        SpringApplication.run(AcademiaOnlineApplication.class, args);
    }
//método dataSource omitido


    @Bean
    public Properties aditionalProperties() {
        Properties props = new Properties();
        props.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        props.setProperty("hibernate.format_sql", "true");
        props.setProperty("hibernate.hbm2ddl.auto", "create");
        return props;
    }

Fala ai Michel, de boa ?

É comum colocarmos essa configuração todo no arquivo application.properties, fora a maneira programática, não me recordo de nenhum outro jeito.

Oi, de boas sim,

Entao deve estar, no contexto do spring boot esse método aditionalProperties() que eu criei, inicialmente ele esta na classe de inicializacao do Spring ja anotado como @Bean mas nao esta sendo lido. De fato eu inseri os parametros necessarios no application.properties e funcionou direito, porem eu gostaria de entender porque nao funcionou com o meu metodo.

Desde ja VLW

solução!

Fala rapazes, tudo bem ?

Tem sempre a forma programática e a ideia de passar os dados no .properties (que vai chamar a forma programática provida pelas classes do pacote autoconfigure do Spring Boot).

O que acontece com o seu código de configuração programática é que o Spring Boot não tem um listener que vai ler seu objeto (bean) Properties pegar os valores das chaves e passar à factory da JPA (que é do projeto spring-orm). Para fazer essa configuração na mão vai ser necessário expor no código de configuração o @Bean LocalContainerEntityManagerFactoryBean (que vai ter essas informações e detalhes do hibernate) e ele sim vai ser lido pelo Spring.

Exemplo:

public class AcademiaOnlineApplication {

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

    // não precisa definir o datasource programaticamente
    // pode ser pelo properties

    @Bean                                    // o bean DataSource pode ser esperado como parâmetro para essa configuração 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setPackagesToScan(new String[] {"br.com.seudominio.seuprojeto.models"});
        emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "create");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.format_sql", "true");

        emf.setJpaProperties(properties);
        return emf;
    }
}

Ou se ainda quiser deixar as propriedades em um método separado para facilitar a organização, você pode sim ter o método que devolve as propriedade expondo um bean, mas desde que você nomeie o bean e faca referencia a ele como dependencia no método que define o bean do EntityManagerFactory.

public class AcademiaOnlineApplication {

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

    @Bean(name="hibernateProperties")
    public Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "create");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.format_sql", "true");

        return properties;
    }

    // não precisa definir o datasource programaticamente
    // pode ser pelo properties

    @Bean                                    // o bean DataSource pode ser esperado como parâmetro para essa configuração 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, 
            @Qualifier("hibernateProperties") Properties properties) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setPackagesToScan(new String[] {"br.com.seudominio.seuprojeto.models"});
        emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        emf.setJpaProperties(properties);
        return emf;
    }
}

Espero ter ajudado. Abraço !

Muito Obrigado mesmo pela resposta, solução, e informação que vem agregar e muito o conhecimento