Java - Obtener datos de dos o más tablas con Hibernate

 
Vista:

Obtener datos de dos o más tablas con Hibernate

Publicado por Maverick (2 intervenciones) el 21/05/2009 03:57:59
Buen día soy nuevo en Hibernate y he logrado construir un aplicativo que obtiene datos de una tabla llamada Libros en web usando hibernate con JSP, por lo que he configurado Hibernate, mapeado mi tabla con XML, y todo hasta el momento funciona perfecto, la única duda que tengo para terminar de comprender generalmente hibernate es cómo le hago para obtener información de dos tablas?. Me explicaré mejor:

He agregado una segunda tabla llamada Editorial que contiene dos campos, la primary key "cveedi" y la descripción de la tabla "edides" a manera de catálogo, y Libros tiene una llave foranea hacia Editorial lo cual genera una relación muchos a uno, varios libros pueden tener un editorial, actualmente los xml de ambas tablas son como sigue:

Libro.hbm.xml:

<!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package = "tutorial">
<class name="tutorial.Libro" table="LIBRO">
<id name="cvelib" column="CVELIB" type="long">
<generator class="native"/>
</id>
<property name="titulo" type="string"/>
<property name="autor" type="string"/>
<many-to-one name = "cveedi" class = "tutorial.Editorial" column = "CVEEDI"/>
</class>
</hibernate-mapping>

Editorial.hbm.xml:

<!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package = "tutorial">
<class name="tutorial.Editorial" table="EDITORIAL">
<id name="cveedi" column="CVEEDI" type="long">
<generator class="native"/>
</id>
<property name="edides" type="string">
<column name="EDIDES" length="50" not-null="true" unique="true"/>
</property>
</class>
</hibernate-mapping>

Las clases son:

Libros.java

/**
* @title 'Proyecto de integración experimental de la capa de persistencia a aplicativos web java Fase 1.'
* @author M@verick
* @version 1.0
* @description 'Clase que contiene el mapeo de objetos de una tabla de MySQL'
* @date 28/april/2009
*/

//paquete propietario.
package tutorial;

/**
* @Class
* @description 'Declaración de clase principal'
* @table hibernate2.libro
*/
public class Libro {

/**
* @attributes
* @description 'Declaración de atributos'
*/

private long cvelib = 0;
private String titulo = "";
private String autor = "";
private Editorial cveedi;

/**
* @gettersSetters
* @description 'declaración de getters y setters'
*/

public long getCvelib() {
return cvelib;
}
public void setCvelib(long cvelib) {
this.cvelib = cvelib;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public String getAutor() {
return autor;
}
public void setAutor(String autor) {
this.autor = autor;
}
public Editorial getCveedi() {
return cveedi;
}
public void setCveedi(Editorial cveedi) {
this.cveedi = cveedi;
}


}//Final de clase principal

Y Editorial.java:

/**
* @title 'Proyecto de integración experimental de la capa de persistencia a aplicativos web java Fase 1.'
* @author M@verick
* @version 1.0
* @description 'Clase que contiene el mapeo de objetos de una tabla de MySQL'
* @date 7/mayo/2009
*/

//paquete propietario
package tutorial;

/**
* @Class
* @description 'Declaración de clase principal'
* @table hibernate2.editorial
*/
public class Editorial {

/**
* @attributes
* @description 'Declaración de atributos'
*/

private long cveedi = 0;
private String edides = "";

/**
* @gettersSetters
* @description 'declaración de getters y setters'
*/

public long getCveedi() {
return cveedi;
}
public void setCveedi(long cveedi) {
this.cveedi = cveedi;
}
public String getEdides() {
return edides;
}
public void setEdides(String edides) {
this.edides = edides;
}

}//Final de clase principal

he logrado obtener la información usando:

Iterator libroAndEditorial = session.createQuery("select libro.titulo, editorial.edides " +
"from Libro libro, Editorial editorial where libro.cveedi = editorial.cveedi").list().iterator();
while (libroAndEditorial.hasNext()) {
Object[] tuple = (Object[])libroAndEditorial.next();
String libro = (String) tuple[0];
String editorial = (String) tuple[1];
System.out.println("Libro = " + libro);
System.out.println("Editorial = " + editorial);
}

Pero creo que no estoy utilizando mucha de la capacidad de Hibernate... ya que como ven no estoy llenando en ningún momento las propiedades de las clases Libro y Editorial, en pocas palabras, creo que si he mapeado bien mis clases, debe de haber alguna manera de que ejecute un HQL de la forma "select Libro.titulo, Editorial.edides from Libro, Editorial"
y que Hibernate haga el join, me llene las propiedades que quiero y únicamente mandarlas a llamar con algo como: "libro.getTitulo();" y "editorial.getEdides();" Lo que pretendo es posible???

Les agradecería si alguien me puede orientar al respecto.

Gracias, espero alguien me pueda contestar a la brevedad...

Salu2.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Obtener datos de dos o más tablas con Hibernate

Publicado por 1a2a3a4a (57 intervenciones) el 21/05/2009 05:05:04
has probado con :

java.util.List libroAndEditorial = session.createQuery("from Editorial").list();

for(int i=0;i<libroAndEditorial.size();i++){
Libro libro=(Libro)(libroAndEditorial .get(i));

System.out.println(libro.getTitulo());
System.out.println(libro. getCveedi().getEdides());

}

algo asi mas o menos
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Obtener datos de dos o más tablas con Hibernate

Publicado por Mario (40 intervenciones) el 21/05/2009 09:14:07
Para empezar yo diría que tienes que cambiar un poco el mapeo de Libros.
Cambia la relación many-to-one que tienes x esto:

<many-to-one name = "editorial" class = "tutorial.Editorial" fetch="select">
<column = "CVEEDI"/>
</many-to-one>

La clase libro tiene que tener como uno de sus atributos un atributo llamado editorial (tal y como se especifica en el name) y del tipo Editorial.

Una vez asegurado de tener eso correctamente prueba la siguiente consulta:

From Libro libro LEFT JOIN FETCH libro.Editorial editorial

Esa consulta debe devolverte una lista de objetos Libro (solamente objetos Libro), que contendrán un atributo editorial, relleno con los datos correspondientes.

Con lo cual, para acceder a editorial.getEdides() deberías hacer lo siguiente:

libro.getEditorial().getEdides();

Si tienes alguna duda o algún problema me comentas ; )
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Obtener datos de dos o más tablas con Hibernate

Publicado por Maverick (2 intervenciones) el 21/05/2009 19:06:42
Buen día Mario...

De ante mando agradezco tu respuesta... hice exactamente lo que me dijiste, de hecho el mapeo de la clase libro quedó de la siguiente manera:

<!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package = "tutorial">
<class name="tutorial.Libro" table="LIBRO">
<id name="cvelib" column="CVELIB" type="long">
<generator class="native"/>
</id>
<property name="titulo" type="string"/>
<property name="autor" type="string"/>
<many-to-one name = "cveedi" class = "tutorial.Editorial" fetch="select">
<column name = "CVEEDI"/>
</many-to-one>
</class>
</hibernate-mapping>

Aqui el Eclipse me marca un error en el fetch, aún así lo corrí..

en la parte de obtener los datos puse lo siguiente:

try{
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
//Query query = session.createQuery("from Libro left join fetch Libro.id_edi Editorial");
Query query = session.createQuery("from Libro libro LEFT JOIN FETCH libro.cveedi Editorial ");
List<Libro> resultado = query.list();
transaction.commit();
session.close();
for(int liCon = 0; liCon <= resultado.size(); liCon++){
Libro libro = resultado.get(liCon);
System.out.println("Clave: " + libro.getCvelib());
System.out.println("Titulo: " + libro.getTitulo());
System.out.println("Autor: " + libro.getAutor());
System.out.println("Editorial: " + libro.getCveedi().getEdides());
}
//return resultado;
}catch(HibernateException e){
throw new RuntimeException(e.getMessage());
}

Al correrlo me marca el error del fetch...

GRAVE: Error parsing XML: XML InputStream(10) Attribute "fetch" must be declared for element type "many-to-one".
org.hibernate.MappingException: Error reading resource: tutorial/datos/Libro.hbm.xml
at org.hibernate.cfg.Configuration.addResource(Configuration.java:452)
at org.hibernate.cfg.Configuration.parseMappingElement(Configuration.java:1263)
at org.hibernate.cfg.Configuration.parseSessionFactory(Configuration.java:1235)
at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1217)
at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1184)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1112)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1098)
at tutorial.ManejadorLibros.<init>(ManejadorLibros.java:45)
at org.apache.jsp.fase1_jsp._jspService(fase1_jsp.java:95)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:581)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Unknown Source)
Caused by: org.hibernate.MappingException: invalid mapping
at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:399)
at org.hibernate.cfg.Configuration.addResource(Configuration.java:449)
... 26 more
Caused by: org.xml.sax.SAXParseException: Attribute "fetch" must be declared for element type "many-to-one".
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.addDTDDefaultAttrsAndValidate(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleStartElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.startElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at org.dom4j.io.SAXReader.read(SAXReader.java:465)
at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:398)
... 27 more

he encontrado en varios tutorial que el fetch puede declararse en <many-to-one> pero en mi eclipse me marca un error, aunque la solución que me dan es: "GRAVE: Error parsing XML: XML InputStream(10) Attribute "fetch" must be declared for element type "many-to-one" que es precisamente lo que estoy haciendo entonces no entiendooo

Sabes la causa de este error??

Agradezco tu atención si deseas pasame por correo tu messenger para agilizar... mi correo es [email protected]

Gracias y saludos...
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Obtener datos de dos o más tablas con Hibernate

Publicado por Mario (40 intervenciones) el 22/05/2009 11:04:38
Ok, mi msn es [email protected], agrégame a ver si coincidimos cuando esté fuera de la oficina.
Por otro lado y siguiendo con el tema... he visto algo que me ha resultado un poco extraño y que quizás tengas mal, observa:

<property name="titulo" type="string"/>
<property name="autor" type="string"/>
<many-to-one name = "cveedi" class = "tutorial.Editorial" fetch="select">
<column name = "CVEEDI"/>
</many-to-one>

Me he fijado en esa porción de código del mapeo, y lo que veo es que para la propiedad name y para la propiedad autor no defines ninguna columna, puede ser que al no definir ninguna columna eclipse interprete que aún no se ha cerrado la etiqueta property.
Fíjate en cómo tengo yo uno de mis campos:

<property name="mailPagador" type="string">
<column name="T_P_MAIL" length="64">
<comment>Correo electrónico del pagador.</comment>
</column>
</property>

La etiqueta comment no es necesaria, pero si la quitas acuerdate de cerrar correctamente la etiqueta column.

Si lo que pasa es que esos campos los tienes en el objeto xq en él cumplen alguna función, pero que no te interesa guardarlos en BD, simplemente no los mapees, que no aparezcan ahí.

Prueba de esa forma y si tampoco va me vuelves a decir que error te marca.

Suerte!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Obtener datos de dos o más tablas con Hibernate

Publicado por ALdo (11 intervenciones) el 27/05/2009 19:00:17
Hola bueno no soy experto en hibernate, pero me parese que el error de fetch es por que en el mapeo pones fetch="select"

<property name="titulo" type="string"/>
<property name="autor" type="string"/>
<many-to-one name = "cveedi" class = "tutorial.Editorial" fetch="select">
<column name = "CVEEDI"/>

y cuando realizas un query haciendo LEFT JOIN FETCH

Query query = session.createQuery("from Libro libro LEFT JOIN FETCH libro.cveedi Editorial ");

Hibernate interpreta que estas usando el fetch="Join" y ya no es un select, nos esi me dejo entender, tu mapeo debe de ser sin el fetch:

<property name="titulo" type="string"/>
<property name="autor" type="string"/>
<many-to-one name = "cveedi" class = "tutorial.Editorial" >
<column name = "CVEEDI"/>

ojala te sirva y funcione

saludos
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar