Hibernate e Postgre com campo campo Serial

Olá pessoal, estou seguindo exemplo do livro Java Persistence, só que uso o Postgre.
O meu problema é com o campo serial do Postgre, se eu colocar o código manual ele executa com sucesso.
No pgAdmin o postgre inseri o código automático.

Acontece a seguinte exceção.

17:06:48,886  WARN JDBCExceptionReporter:71 - SQL Error: 0, SQLState: 23502
Exception in thread "main" 17:06:48,901 ERROR JDBCExceptionReporter:72 - ERROR: null value in column "message_id" violates not-null constraint
org.hibernate.exception.ConstraintViolationException: could not insert: [hello.Message]
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:40)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2093)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2573)
	at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:47)
	at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
	at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
	at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
	at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
	at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
	at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
	at hello.HelloWorld.main(HelloWorld.java:26)
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "message_id" violates not-null constraint
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1548)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1316)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:191)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:452)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:351)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:305)
	at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
	at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:33)
	... 16 more

Parte do código


Session session = HibernateUtil.getSessionFactory().openSession();
		
Transaction tx = (Transaction) session.beginTransaction();
		
Message message = new Message("Hello World");
//message.setId(new Long(4));
Long msgId = (Long) session.save(message);
		
tx.commit();
session.close();

Grato!

Como foi que vc mapeou a classe Message?

Usei um arquivo xml Message.hbl.xml que está no mesmo pacote da classe.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class
        name="hello.Message"
        table="MESSAGES">

        <id
            name="id"
            column="MESSAGE_ID">
            <generator class="native"/>
        </id>

        <property
            name="text"
            column="MESSAGE_TEXT"/>

        <many-to-one
            name="nextMessage"
            cascade="all"
            column="NEXT_MESSAGE_ID"
            foreign-key="FK_NEXT_MESSAGE"/>

    </class>

</hibernate-mapping>

Cara, em primeiro lugar, logo de cara aconselho vc a usar anotacao pra mapear suas classes…
é muito mais simples, vc nao precisa criar um xml pra cada classe.

Da uma olhada nesse video aqui:

http://blog.caelum.com.br/video/jpa/beginning-with-jpa.html

Garanto que nunca mais vai querer mapear uma classe com xml!

Essa apostila tambem vai te ajudar:

ftp://raphaela:web@users.dca.ufrn.br/UnP2007/Hibernate_Anotacoes.pdf

ja que vc ta começando com hibernate, que use logo ANNOTATIONS

Agradeço, mas é que estou acompanhado os exemplos do livro e estou com Postgre e não com.
Estou na parte 2 que ensina a fazer com Annotation. Vou fazer com Annotation.

Grato pela ajuda!

Muito obrigado pela dica, a apostila ensina como fazer com o Postgre ftp://users.dca.ufrn.br/UnP2007/Hibernate_Anotacoes.pdf.
No caso tive que criar uma sequence com nome hibernate_sequence.

[quote=Alberes]Muito obrigado pela dica, a apostila ensina como fazer com o Postgre ftp://users.dca.ufrn.br/UnP2007/Hibernate_Anotacoes.pdf.
No caso tive que criar uma sequence com nome hibernate_sequence.

[/quote]

Com o Postgre eu costuimo fazer assim e funciona muito bem

@Entity
@SequenceGenerator(name="foo_id_seq", sequenceName="foo_id_seq")
public class Foo {
   @Id
   @GeneratedValue(generator="foo_id_seq", strategy=GenerationType.SEQUENCE)
   private long id;

   //...
}

Assim o Hibernate cria sozinho uma sequência para cada entidade persistente que eu defino.

Gostei da sua dica, mas não consegui executar, simplesmente copiei a parte das anotações.
Tem que fazer mais alguma coisa?
Para cria a tabela eu usei Serial.

create table MESSAGES (
        MESSAGE_ID SERIAL,
        MESSAGE_TEXT varchar(255),
        NEXT_MESSAGE_ID bigint,
        primary key (MESSAGE_ID)
);
@Entity
@SequenceGenerator(name="foo_id_seq", sequenceName="foo_id_seq")
@Table(name="MESSAGES", schema="anotacoes")
public class Message {
	
	@Id
	@GeneratedValue(generator="foo_id_seq", strategy=GenerationType.SEQUENCE) 
	@Column(name="MESSAGE_ID")
	private Long id;
09:53:03,002  WARN JDBCExceptionReporter:71 - SQL Error: 0, SQLState: 42P01
09:53:03,002 ERROR JDBCExceptionReporter:72 - ERROR: relation "hibernate_sequence" does not exist
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not get next sequence value
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:96)
	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:98)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
	at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
	at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
	at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
	at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
	at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
	at hello.HelloWorld.main(HelloWorld.java:26)
Caused by: org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1548)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1316)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:191)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:452)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:351)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:255)
	at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
	at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:75)
	... 10 more

Não amigo, desse jeito que eu fiz, o Hibernate considera uma sequência com o nome definido na anotação. Se não existir uma sequência neste campo (no caso o id) ele cria uma nova com esse nome. Caso já exista uma sequência com esse nome, ele usa.
“foo_id_seq” foi apenas um exemplo!
Você vai precisar colocar o nome correto para sua sequência nestes campos.

Se você nao souber o nomeda sequência, vai no pgadim e dá uma olhada(ou no console com \d e o nome da sua tabela, ele vai mostrar qual sequence está associada ao campo id).

Olá,

Então cassio, estou com o mesmo problema, do amigo ai em cima.

Segui suas dicas, consegui persistir uma entidade no banco, só que o id dela ficou com o valor = 100. Eu tinha apenas 1 registro no Banco, era pra ficar com o id = 2!?!

Uso uma tabela com campo id SERIAL no postgreSQl.

Obrigado!

Cara, verifica como você criou o sequence no banco, provavelmente é esse o problema.
tem que começar em 1 e incrementar 1

[quote]
Olá,

Então cassio, estou com o mesmo problema, do amigo ai em cima.

Segui suas dicas, consegui persistir uma entidade no banco, só que o id dela ficou com o valor = 100. Eu tinha apenas 1 registro no Banco, era pra ficar com o id = 2!?!

Uso uma tabela com campo id SERIAL no postgreSQl.

Obrigado![/quote]

Vish cara eu não criei nada rs, eu só peguei a sequence que aparecia lá no pgAdmin.

Acho que deve ser isso então né?

Obrigado!

O meu problema foi esse, não tinha o incremento, então violava a regra PK e pelo que você descreveu sim.

[]s

Deu certo aqui!

Criei a sequence no PostgreSQl

CREATE SEQUENCE nomedasequence;

E usei “increment” no xml do hibernete.

<id name="id" type="int">
 <column name="ID" />
 <generator class="increment" />
</id>

Ou, com annotations usei “sequence”…

@Id
@SequenceGenerator(name = "sequence", sequenceName = "nomedasequence", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
@Column(name="id")
public int getId() {
	return id;
}

Mas enfim deu tudo certo!

Só uma duvida! Quando eu apago um registro na tabela, tem como eu diminuir o “sequence” da tabela de alguma forma?

Obrigado!

Não faz sentido, “sequence” é incremental e sequencial, a cada consulta na sequence é adicionado mais 1.
Você pode atualizar a sequence, mas se estiver usando esse valor em um campo da tabela como chave primária o unike key o banco lança uma bela Exception de violação de chave primária ou unique key.

Um exemplo, você tem uma tabela e usa esse sequence para gerar a pk da mesma, com 1 registros 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. Depois você apagar o registro 5, se você atualizar o sequence para 5 o próximo valor do sequence será 6, ma o 6 já está em uso, então o BD lançara uma Exception.

Bom dia Alberes,

Acho que eu esqueci deste detalhe :oops:

Obrigado! t+

Oi Alberes,

Ta acontecendo uma coisa estranha aqui comigo queria saber se já passo por isso, ou saiba o que possa ser.

bom vamos lá, deixa eu postar meus códigos hehehe

import javax.persistence.*;

@Entity
@Table(name = "aduser")
public class User {

	private long id;
	private String nome;
	private String senha;

	User() {
		// TODO Auto-generated constructor stub
	}

	public User(String nome, String senha) {
		super();
		this.nome = nome;
		this.senha = senha;
	}

	@Id
	@SequenceGenerator(name = "seq", sequenceName = "user_seq", allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
	public long getId() {
		return id;
	}

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

	@Column(unique = true)
	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

}
CREATE SEQUENCE user_seq MINVALUE 0 START 0;
CREATE TABLE aduser
(
  id integer NOT NULL DEFAULT nextval('user_seq'::regclass),
  nome character varying(255),
  senha character varying(255),
  CONSTRAINT user_pkey PRIMARY KEY (id),
  CONSTRAINT nome_key UNIQUE (nome)
)
WITH (OIDS=FALSE);
ALTER TABLE aduser OWNER TO postgres;

Acontece o seguinte, quando eu salvo um usuario no banco rodando a aplicação pela primeira vez, a “sequence” do banco não incrementa, o user fica com o id = 0. Então eu fui verificar a sequence no postgre(user_seq) e vi que ela não incrementou, permaneceu 0. Então exclui o registro manualmente, e salvei o user novamente dai sim ficou com o id = 1. :?:

Interesante é que se depois disso, eu remover novamente o user manualmente e setar o “user_seq” pra 0, como estava no principio, então de alguma forma quando eu salvo o user, funciona tudo normal. A sequence passa de 0 pra 1 e o user é gravado com o id = 1;

enfim é meio doido :shock:

Espero que consiga entender, e se possível possa me ajudar com isso.

Se alguém já passou por isso e sabe do que estou falando e puder ajudar também…

Obrigado!
t+

Tenta isso Felipe.

Seu código

CREATE SEQUENCE user_seq MINVALUE 0 START 0; 

Opções para criar sequence.

CREATE [ TEMPORARY | TEMP ] SEQUENCE name [ INCREMENT [ BY ] increment ]
    [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
    [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]

[color=red]Tenta colocar a opção increment, pelo que lembro, caso não seja especificado ele mantém o valor antigo.[/color]

CREATE SEQUENCE user_seq MINVALUE 0 START 0 INCREMENT 1; 

Acho que não precisa dessa parte do código, faz um teste.

nextval('user_seq'::regclass)

Ok, vou tentar aqui!

Valeu! :wink: