Problema ao utilizar @OneToOne - não inseri apenas atualiza

3 respostas
leokaos

Seguinte: tenho a tabela tab_imovel que contém os dados do imóvel, e a tabela tab_anuncio, que quando o imóvel for anunciado, o usuário coloca as informações do anúncio. entretanto não existe a obrigatoriedade de quando o imóvel ser adicionado no sistema, ele criar a tupla em tab_anuncio, pois apenas uma parte do banco é anunciado, cerca de 1/3 é anunciado. Então, quando o imóvel deve ser anunciado o sistema confirma se já existe a tupla em tab_anuncio, se existir eu consigo manipular normalmente com o saveOrUpdate(), entretanto quando eu tento criar uma nova tupla em tab_anuncio para um imóvel que nunca foi criado o anuncio, ele tenta dar um update:

Hibernate: 
    update
        tab_anuncio
    set
        itens=?,
        texto=?,
        textoAnuncio=? 
    where
        referencia=?

onde referência é o código do imóvel, na tab_imovel, que tb é PK. Como faço para ao invés de ele der um update ele dar um insert, caso não exista?

mapeamentos:
Imovel.class

@Entity
@Table(name="tab_imovel")
public class Imovel implements Serializable{
    
    @Id
    @Column(name="referencia",nullable=false,length=20)
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long referencia;
    //outros atributos, get e set.

ImovelAnuncio.class

@Entity
@Table(name="tab_anuncio")
public class ImovelAnuncio implements Serializable{
    
    @PrimaryKeyJoinColumn
    @OneToOne(targetEntity=Usuario.class,fetch= FetchType.EAGER,optional=false)
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.LOCK})
    @JoinColumns(@JoinColumn(name="referencia"))
    private Imovel imovel;
    
    @Id
    @Column(name="referencia",nullable=false)
    @GeneratedValue(generator="imovelZap")
    @GenericGenerator(name="imovelZap",strategy="foreign",parameters={@Parameter(name="property",value="referencia")})
    private Long imovelID;

    //outros atributos, get e set.

ou seja, caso a tupla da referencia 50, por exemplo, ainda não exista ele der um insert ao invés de update.

para gravar já tentei das duas maneiras

Maneira 1

ImovelAnuncio anu = new ImovelAnuncio();
        anu.setImovel(ImovelDAO.load(50));
        ImovelAnuncioDAO.save(anu);

e Maneira 2

ImovelAnuncio anu = new ImovelAnuncio();
        anu.setImovelID(ImovelDAO.load(50).getReferencia());
        ImovelAnuncioDAO.save(anu);

Nos dois jeitos o erro:

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
	at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:81)
	at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:73)
	at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.checkRowCounts(BatchingBatch.java:133)
	at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:110)
	at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:101)
	at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:161)
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:162)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:268)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:187)

Pois, como coloquei em cima ele faz um update, e como não existe ainda a tupla ele dá erro.

vlw

3 Respostas

drsmachado

Então, desaconselho o uso de saverOrUpdate…
Utilize o método save para salvar e o update para atualizar, separadamente.

Isso, por quê, o hibernate irá tentar salvar todas as entities que não possuem valor no id. Caso haja um valor qualquer, ele tentará realizar o update.

Portanto, desvincule essas ações, tome o controle, fazendo você mesmo a filtragem de quando é insert e quando é update.

leokaos

Vlw a resposta rápida!

realmente usando o save() ao invés do saveOrUpdate() funcionou, entretanto queria entender pq naum funcionou, meu mapeamento tá errado?

drsmachado

O mapeamento não está errado, o comportamento do hibernate é que não ajuda nisso.
Não sei como você está controlando o id do Imovel e se este id está sendo provido pela lógica da aplicação ou pelo hibernate.
De qualquer forma, se a tabela estiver fazendo o auto_increment (caso MySQL) da coluna id, o strategy é dispensável.

De qualquer forma (2) ainda prefiro manter o controle das coisas em separado.

Criado 6 de janeiro de 2012
Ultima resposta 6 de jan. de 2012
Respostas 3
Participantes 2