Gravando imagens com hibernate no sqlserver 2005

Bom dia pessoal,

Estou com um problema com a minha camada de persistência de uma aplicação desktop que desenvolvi. Essa aplicação foi feita sob demanda com uma série de restrições por parte do cliente: a base de dados tinha que ser SQL Server (pq os desenvolvedores que vão dar manutenção nisso depois não sabem usar outra base de dados -_-’) e é necessário gravar uma quantidade X de imagens na base de dados (eu sei que isso não é recomendado, também prefiro gravar no filesystem…mas os “desenvolvedores” não arredaram pé dessa exigência…).

O que ocorre é que, antes de ficar sabendo da necessidade de ser MS SQL Server, eu fiz a persistência em uma base de dados Postgres. Funcionou às mil maravilhas, as imagens eram gravadas em um campo bytea e no java eu referenciava com byte[]. Simples assim…no SQL Server as coisas começam a virar um pesadelo…

Criei a tabela no banco com o campo sendo do tipo image (teste tbm com varbinary e recebi o mesmo erro), não mudei a forma de representação no java (continua sendo byte[]) e a forma como eu tento persistir continua a mesma. Porém na hora de persistir, recebo um Data Truncation Exception. Qual o tipo de dados que deveria ser utilizado? E como ele deve ser mapeado no Hibernate?

Segue o mapeamento da entidade:

@Lob
    @Column(name = "imagem")
    private byte[] imagem;

e a forma como eu gravo a imagem no atributo antes de persistir o objeto:

files = crawler.listAllFiles(path,nomeImagem);
System.out.println(files.size());
if(!files.isEmpty()){
   try {
      fi = new FileInputStream(files.get(0).getAbsolutePath());
      files = null;
   } catch (FileNotFoundException ex) {
      Logger.getLogger(CriteriaMatcher.class.getName()).log(Level.SEVERE, null, ex);
   }
   try {
      while ((bytesRead = fi.read(buffer)) != -1) {
         arrayOutputStream.write(buffer, 0, bytesRead);
       }
   } catch (IOException ex) {
      Logger.getLogger(CriteriaMatcher.class.getName()).log(Level.SEVERE, null, ex);
   }
   try {
      arrayOutputStream.close();
   } catch (IOException ex) {
      Logger.getLogger(CriteriaMatcher.class.getName()).log(Level.SEVERE, null, ex);
   }
   e.setImagem(arrayOutputStream.toByteArray());
}

Alguma idéia?

Tentou criar a coluna como BLOB no banco? Eu acho que é o mais recomendado para esses casos:
http://technet.microsoft.com/en-us/library/cc917636.aspx

Obrigado visola pela resposta. Mas pelo que eu li no texto que você me encaminhou, o SQL Server trata os campos do tipo text, ntext e image como os seus “blobs”.

Eu tentei alterar o campo para ntext e text e para ambos os casos aparece uma stacktrace diferente agora:

GRAVE: Could not synchronize database state with session
org.hibernate.exception.DataException: could not insert: [dao.entities.Empresa]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2267)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
        at dao.controller.BaseDao.persistEmpresa(BaseDao.java:37)
        at matcher.CriteriaMatcher.parseHtml(CriteriaMatcher.java:131)
        at htmlparser.Main.main(Main.java:57)
Caused by: java.sql.SQLException: Conflito no tipo de operando: varbinary é incompatível com text
        at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:368)
        at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2816)
        at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2254)
        at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:631)
        at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:584)
        at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:546)
        at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:505)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2247)
        ... 14 more
Exception in thread "main" javax.persistence.RollbackException: Error while commiting the transaction
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:71)
        at dao.controller.BaseDao.persistEmpresa(BaseDao.java:37)
        at matcher.CriteriaMatcher.parseHtml(CriteriaMatcher.java:131)
        at htmlparser.Main.main(Main.java:57)
Caused by: org.hibernate.exception.DataException: could not insert: [dao.entities.Empresa]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2267)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
        ... 3 more
Caused by: java.sql.SQLException: Conflito no tipo de operando: varbinary é incompatível com text
        at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:368)
        at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2816)
        at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2254)
        at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:631)
        at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:584)
        at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:546)
        at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:505)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2247)
        ... 14 more
Java Result: 1

Segundo o erro, o tipo que o Hibernate usa para persistir é o varbinary, logo, eu converti o campo na tabela para varbinary(max)…então eu passo a receber o seguinte erro:

GRAVE: Could not synchronize database state with session
org.hibernate.exception.DataException: could not insert: [dao.entities.Empresa]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2267)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
        at dao.controller.BaseDao.persistEmpresa(BaseDao.java:37)
        at matcher.CriteriaMatcher.parseHtml(CriteriaMatcher.java:131)
        at htmlparser.Main.main(Main.java:57)
Caused by: java.sql.DataTruncation: Data truncation
        at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:382)
        at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2816)
        at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2254)
        at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:631)
        at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:584)
        at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:546)
        at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:505)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2247)
        ... 14 more
Exception in thread "main" javax.persistence.RollbackException: Error while commiting the transaction
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:71)
        at dao.controller.BaseDao.persistEmpresa(BaseDao.java:37)
        at matcher.CriteriaMatcher.parseHtml(CriteriaMatcher.java:131)
        at htmlparser.Main.main(Main.java:57)
Caused by: org.hibernate.exception.DataException: could not insert: [dao.entities.Empresa]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2267)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
        ... 3 more
Caused by: java.sql.DataTruncation: Data truncation
        at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:382)
        at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2816)
        at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2254)
        at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:631)
        at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:584)
        at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:546)
        at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:505)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2247)
        ... 14 more
Java Result: 1

Que é exatamente o data truncation que eu recebia quando o campo na tabela era image

Não custa perguntar. Mas pelo que vi por aí, esse erro que você está tendo acontece quando a quantidade de bytes que está sendo colocado não cabe na coluna. Talvez a imagem seja muito grande ou você declarou a coluna como muito pequena. Chegou a verificar isso?

Resolvido! Na realidade, acho que era uma incompatibilidade do usuário com a base de dados microsoft, rs…

tudo que eu precisei fazer foi mandar os scripts de geração de código do nb gerar novamente as classes de entidade com base no schema do bd. Daí ele mapeou a imagem como:

@Lob
@Column(name = "imagem")
private Serializable imagem;

e a parte da gravação continuou igual. Outra coisa que foi necessária foi rever os campos VARCHAR do pg para colocar como NVARCHAR(x) no sql server, onde X é quantidade de posições. Em alguns casos, com campos de texto livre, ficou como NVARCHAR(max).

Valew pela força visola.