java - generationtype - id hibernate
Nombre de objeto inválido para Hibernate Sequence Generator (1)
Estoy desarrollando una aplicación que accede a una base de datos que ejecuta SQL Server 2012 a través del marco de Hibernate. Sin embargo, no puedo entender cómo hacer que funcione una instancia de la anotación SequenceGenerator; Obtengo una excepción cada vez que intento guardar una nueva instancia de objeto en la tabla de mi base de datos. La clase que se guardará es la siguiente:
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
@Entity
@Table(name="MESSAGES")
public class Message implements Serializable {
private static final long serialVersionUID = -3535373804021266134L;
@Id
@Column(name="MESSAGE_ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MESSAGE_GEN")
@SequenceGenerator(name="MESSAGE_GEN", sequenceName="MESSAGE_SEQ", initialValue=1, allocationSize=1)
private Long id;
@Column(name="TEXT")
private String text;
public Message(String text) {
this.text = text;
}
public Long getId() {
return id;
}
public String getText() {
return text;
}
}
Un escenario provocador de problemas podría ser la siguiente transacción:
import org.hibernate.Session;
public class Manager {
public static void main(String[] args) {
Session session = Database.getSessionFactory().getCurrentSession();
session.beginTransaction();
Message message = new Message("Hello, World!");
session.save(message);
session.getTransaction().commit();
Database.getSessionFactory().close();
}
}
Esto da como resultado la siguiente traza de pila relacionada con la secuencia de identificador:
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:123)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:91)
at org.hibernate.id.SequenceGenerator.generateHolder(SequenceGenerator.java:122)
at org.hibernate.id.SequenceHiLoGenerator.generate(SequenceHiLoGenerator.java:73)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:715)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:707)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:702)
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 org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:356)
at com.sun.proxy.$Proxy8.save(Unknown Source)
at dk.radiometer.tests.hibernate.service.Manager.doTransaction(Manager.java:35)
at dk.radiometer.tests.hibernate.service.Manager.main(Manager.java:16)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid object name ''MESSAGE_SEQ''.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1515)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:404)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:350)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:180)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:155)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:285)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:82)
... 19 more
El problema parece estar relacionado con el nombre de la secuencia. Supongo que necesito crear manualmente una tabla de secuencias para que Hibernate las use, sin embargo, no sé cómo hacer esto y no he podido encontrar un recurso que parezca relacionado con mi entorno. Si este es realmente el problema, por favor redirigirme a cierta documentación para el protocolo a seguir. Además, estoy usando la siguiente configuración programática de Hibernate:
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class Database {
private static final SessionFactory SESSION_FACTORY = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
Configuration cfg = buildConfiguration();
ServiceRegistry sr = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
SessionFactory sf = cfg.buildSessionFactory(sr);
return sf;
} catch (Throwable t) {
System.err.println("Initial SessionFactory creation failed: " + t);
throw new ExceptionInInitializerError(t);
}
}
private static Configuration buildConfiguration() {
return new Configuration()
.addAnnotatedClass(Message.class)
.setProperty("hibernate.connection.driver_class", "com.microsoft.sqlserver.jdbc.SQLServerDriver")
.setProperty("hibernate.connection.url", "jdbc:sqlserver://SERVER_NAME;databaseName=DATABASE_NAME;integratedSecurity=true;")
.setProperty("hibernate.connection.pool_size", "1")
.setProperty("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect")
.setProperty("hibernate.current_session_context_class", "thread")
.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.internal.NoCacheProvider")
.setProperty("hibernate.show_sql", "true")
.setProperty("hibernate.hbm2ddl.auto", "update");
}
public static SessionFactory getSessionFactory() {
return SESSION_FACTORY;
}
}
¡Gracias por adelantado!
La solución a este problema es agregar el catálogo y las propiedades de esquema a su anotación @Table.
@Table(name="<<TableName>>", catalog="<<DatabaseName>>", schema="SchemaName")
p.ej
@Table(name="EVENTS", catalog="EVENTMANAGER", schema="DBO")
- El catálogo hace referencia al nombre de la base de datos a la que pertenece la tabla dada.
- El esquema hace referencia al contenedor (utilizando la definición de Oracle) al que pertenece la base de datos, en Microsoft SQL Server, las bases de datos generalmente se crean bajo el esquema del Operador de base de datos (DBO).
por ejemplo, Hibernata Mapping File (hbm) que funciona para mí.
<class name="Event" table="EVENTS" catalog="EVENTMANAGER" schema="DBO">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title" column="TITLE" not-null="true"/>
</class>