Hibernate Annotations com Sequence e Composite Primary Keys

Boa tarde pessoal.
Tenho uma tabela com chave composta pelos campos “cd_cliente” e “cd_usuario” onde o campo “cd_usuario” utiliza uma sequence para ser incrementado.
Estou enfrentando o seguinte problema: não consigo criar o mapeamento para tal situação.
Já procurei, testei de n formas e nada.

Bom, o ponto mais próximo que cheguei é o seguinte, uma classe chamada Usuario.java e uma UsuarioPK.java, como seguem os códigos:

Usuario.java

@Entity
@Table(name="usuario")
@IdClass(UsuarioPK.class)
@NamedQuery( name  = "usuariosAtivos", 
        	 query = "SELECT o " +
                	 "  FROM Usuario o " +
                	 " WHERE o.flAtivo = 'S'")
public class Usuario extends GenericEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name="cd_cliente", nullable=false)
	private long cdCliente;
	
	@Id
	@Column(name="cd_usuario", nullable=false)
	@SequenceGenerator(name="gen_usuario", sequenceName="usuario_cd_usuario_seq", initialValue=1, allocationSize=1)
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="gen_usuario")
	private long cdUsuario;

	@Column(name="id_usuario")
	private String idUsuario;
	
	@Column(name="ds_senha")
	private String dsSenha;

	@Column(name="fl_ativo")
	private String flAtivo;

    public Usuario() {
    }
    // getters and setters
}

UsuarioPK.java

public class UsuarioPK implements Serializable {
	
	private long cdCliente;
	private long cdUsuario;

    public UsuarioPK() {
    }
    
    public UsuarioPK(Long cdCliente, Long cdUsuario) {
        this.cdCliente = cdCliente;
        this.cdUsuario = cdUsuario;
    }

	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof UsuarioPK)) {
			return false;
		}
		UsuarioPK castOther = (UsuarioPK)other;
		return 
			(this.cdCliente == castOther.cdCliente)
			&& (this.cdUsuario == castOther.cdUsuario);

    }
    
	public int hashCode() {
		final int prime = 31;
		int hash = 17;
		hash = hash * prime + ((int) (this.cdCliente ^ (this.cdCliente >>> 32)));
		hash = hash * prime + ((int) (this.cdUsuario ^ (this.cdUsuario >>> 32)));
		
		return hash;
    }
}

DDL da tabela usuario:

CREATE TABLE "public"."usuario" (
  "cd_cliente" NUMERIC(6,0) NOT NULL, 
  "cd_usuario" SERIAL, 
  "id_usuario" VARCHAR(32) NOT NULL, 
  "ds_senha" VARCHAR(256) NOT NULL, 
  "fl_ativo" CHAR(1) DEFAULT 'S'::bpchar NOT NULL, 
  CONSTRAINT "usuario_pkey" PRIMARY KEY("cd_cliente", "cd_usuario")
) WITH OIDS;

A exceção ocorre quando vou fazer um select ou insert, é a seguinte:

Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
	at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
	at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:76)
	at br.com.intellective.eluck.model.persistence.UsuarioDAO.findAll(UsuarioDAO.java:22)
	at br.com.intellective.eluck.view.mbean.TesteMBean.getMensagemTeste(TesteMBean.java:22)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at javax.el.BeanELResolver.getValue(BeanELResolver.java:62)
	at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:54)
	at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:72)
	at org.apache.el.parser.AstValue.getValue(AstValue.java:118)
	at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
	at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:102)
	... 49 more
Caused by: org.hibernate.exception.SQLGrammarException: could not execute query
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
	at org.hibernate.loader.Loader.doList(Loader.java:2231)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)
	at org.hibernate.loader.Loader.list(Loader.java:2120)
	at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:401)
	at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:361)
	at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
	at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1148)
	at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
	at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:67)
	... 61 more
Caused by: org.postgresql.util.PSQLException: ERROR: column usuario0_.cdcliente does not exist
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1592)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1327)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:193)
	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 org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
	at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
	at org.hibernate.loader.Loader.doQuery(Loader.java:697)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
	at org.hibernate.loader.Loader.doList(Loader.java:2228)
	... 69 more

A linha: Caused by: org.postgresql.util.PSQLException: ERROR: column usuario0_.cdcliente does not exist da exceção é onde mostra o verdadeiro problema que estou enfrentando.

Vale lembrar que estou utilizando: JSF 2.0, PostgreSQL 8.1, Tomcat 6 e Hibernate 3.
Obs.: Se na classe Usuario.java eu comentar as annotations: @IdClass(UsuarioPK.class) e @Id (do campo cdCliente) eu consigo fazer a consulta e o insert normalmente, ou seja, com essas duas linhas comentadas funciona, mas desse modo o mapeamento fica diferente da modelagem do banco de dados.
Só para facilitar segue o trecho de código da classe Usuario.java com esses dois comentários:

@Entity
@Table(name="usuario")
//@IdClass(UsuarioPK.class)
@NamedQuery( name  = "usuariosAtivos", 
        	 query = "SELECT o " +
                	 "  FROM Usuario o " +
                	 " WHERE o.flAtivo = 'S'")
public class Usuario extends GenericEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	
	//@Id
	@Column(name="cd_cliente", nullable=false)
	private long cdCliente;
...

Desde já agradeço a atenção de todos.

Leandro,

fiz uma classe de teste com o seguinte código:

		Usuario user = new Usuario();
		user.setCdCliente(1);
		user.setIdUsuario("Bortolotto");
		user.setDsSenha("3333");
		user.setFlAtivo("S");
		tx.begin();
		em.persist(user);
		tx.commit();

Capturei a seguinte causa de exceção:

Caused by: java.sql.BatchUpdateException: Entrada em lote 0 insert into usuario1 (ds_senha, fl_ativo, id_usuario, cdCliente, cdUsuario) values (3333, S, Bortolotto, 1, 0) foi abortada. Chame getNextException para ver a causa.

procurei o resultado de getNextException() e verifiquei o seguinte:

ERROR: null value in column “cd_cliente” violates not-null constraint

Ora, como eu setei a propriedade cdCliente (que no banco se chama cd_cliente) e verificando que o insert gerado foi “insert into usuario1 (ds_senha, fl_ativo, id_usuario, cdCliente, cdUsuario)”, percebi que os nomes das duas últimas colunas estavam errados.

Anotei então a classe UsuarioPK da seguinte maneira:

@Column(name="cd_cliente")
private long cdCliente;
@Column(name="cd_usuario")
private long cdUsuario;

Isso fez com que o insert fosse gerado de maneira correta e funcionou!

Com a query não tive problema.

Qualquer coisa, estamos por aqui.

Abraços!

:smiley:

Isso realmente resolveu o problema.
Apenas um detalhe, da maneira que eu postei funciona com o toplink, mas não com o hibernate.

Muito obrigado.