Para los siguientes ejemplos se requiere:
Estructura de los directorios de hibernate
Estructura de los directorios ejemplo
Ejemplo de Almacenamiento y Recuperación de un objeto
El ejemplo consiste en crear un objeto que tenga las características de un Track (canción), poder manipularlo en una aplicación, almacenarlo de manera persistente y poder recuperarlo posteriormente.
Archivo build.xml para generar los códigos, compilar, generar los esquemas.
1:<?xml version="1.0"?> 2:<project name="Harnessing Hibernate: The Developer's Notebook" 3: default="db" basedir="."> 4: 5: <!-- Set up properties containing important project directories --> 6: <property name="source.root" value="src"/> 7: <property name="class.root" value="classes"/> 8: <property name="lib.dir" value="lib"/> 9: <property name="data.dir" value="data"/> 10: 11: <!-- Set up the class path for compilation and execution --> 12: <path id="project.class.path"> 13: <!-- Include our own classes, of course --> 14: <pathelement location="${class.root}" /> 15: <!-- Include jars in the project library directory --> 16: <fileset dir="${lib.dir}"> 17: <include name="*.jar"/> 18: </fileset> 19: </path> 20: 21: <target name="db" description="Runs HSQLDB database management UI 22:against the database file--use when application is not running"> 23: <java classname="org.hsqldb.util.DatabaseManager" 24: fork="yes"> 25: <classpath refid="project.class.path"/> 26: <arg value="-driver"/> 27: <arg value="org.hsqldb.jdbcDriver"/> 28: <arg value="-url"/> 29: <arg value="jdbc:hsqldb:${data.dir}/music"/> 30: <arg value="-user"/> 31: <arg value="sa"/> 32: </java> 33: </target> 34: 35: <!-- Teach Ant how to use Hibernate's code generation tool --> 36: <taskdef name="hbm2java" 37: classname="net.sf.hibernate.tool.hbm2java.Hbm2JavaTask" 38: classpathref="project.class.path"/> 39: 40: <!-- Generate the java code for all mapping files in our source tree --> 41: <target name="codegen" depends="prepare" 42: description="Generate Java source from the O/R mapping files"> 43: <hbm2java output="${source.root}"> 44: <fileset dir="${source.root}"> 45: <include name="**/*.hbm.xml"/> 46: </fileset> 47: </hbm2java> 48: </target> 49: 50: <!-- Create our runtime subdirectories and copy resources into them --> 51: <target name="prepare" description="Sets up build structures"> 52: <mkdir dir="${class.root}"/> 53: 54: <!-- Copy our property files and O/R mappings for use at runtime --> 55: <copy todir="${class.root}" > 56: <fileset dir="${source.root}" > 57: <include name="**/*.properties"/> 58: <include name="**/*.hbm.xml"/> 59: </fileset> 60: </copy> 61: </target> 62: 63: <!-- Compile the java source of the project --> 64: <target name="compile" depends="prepare" 65: description="Compiles all Java classes"> 66: <javac srcdir="${source.root}" 67: destdir="${class.root}" 68: debug="on" 69: optimize="off" 70: deprecation="on"> 71: <classpath refid="project.class.path"/> 72: </javac> 73: </target> 74: 75: <!-- Generate the schemas for all mapping files in our class tree --> 76: <target name="schema" depends="compile" 77: description="Generate DB schema from the O/R mapping files"> 78: 79: <!-- Teach Ant how to use Hibernate's schema generation tool --> 80: <taskdef name="schemaexport" 81: classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask" 82: classpathref="project.class.path"/> 83: 84: <schemaexport properties="${class.root}/hibernate.properties" 85: quiet="no" text="no" drop="no"> 86: <fileset dir="${class.root}"> 87: <include name="**/*.hbm.xml"/> 88: </fileset> 89: </schemaexport> 90: </target> 91: 92: <target name="ctest" description="Creates and persists some sample data" 93: depends="compile"> 94: <java classname="com.oreilly.hh.CreateTest" fork="true"> 95: <classpath refid="project.class.path"/> 96: </java> 97: </target> 98: 99: <target name="qtest" description="Run a simple Hibernate query" 100: depends="compile"> 101: <java classname="com.oreilly.hh.QueryTest" fork="true"> 102: <classpath refid="project.class.path"/> 103: </java> 104: </target> 105: 106:</project> |
Archivo de propiedades de la base de datos
hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect hibernate.connection.driver_class=org.gjt.mm.mysql.Driver hibernate.connection.url=jdbc:mysql://localhost:9097/hibernate hibernate.connection.username=root hibernate.connection.password=lolo |
Archivo para genera los logs en cada ejecución
### direct log messages to stdout ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### direct messages to file hibernate.log ### ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=warn, stdout log4j.logger.net.sf.hibernate=info ### log just the SQL ### log JDBC bind parameters ### ### log schema export/update ### ### log cache activity ### ### enable the following line if you want to track down
connection ### |
Archivo Track.hbm.xml que contiene la definición del objeto que se desea implementar
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: 7: <class name="com.oreilly.hh.Track" table="TRACK"> 8: <meta attribute="class-description"> 9: Represents a single playable track in the music database. 10: @author Jim Elliott (with help from Hibernate) 11: </meta> 12: 13: <id name="id" type="int" column="TRACK_ID"> 14: <meta attribute="scope-set">protected</meta> 15: <generator class="native"/> 16: </id> 17: 18: <property name="title" type="string" not-null="true"/> 19: 20: <property name="filePath" type="string" not-null="true"/> 21: 22: <property name="playTime" type="time"> 23: <meta attribute="field-description">Playing time</meta> 24: </property> 25: 26: <property name="added" type="date"> 27: <meta attribute="field-description">When the track was created</meta> 28: </property> 29: 30: <property name="volume" type="short" not-null="true"> 31: <meta attribute="field-description">How loud to play the track</meta> 32: </property> 33: 34: </class> 35:</hibernate-mapping> |
Generamos el codigo Track.java
digital@localhost:~/SourceExamples/SourceExamples/ch02>
ant codegen Buildfile: build.xml codegen: BUILD SUCCESSFUL |
Clase Track generada con Hibernate
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import java.util.Date; 5:import org.apache.commons.lang.builder.ToStringBuilder; 6: 7: 8:/** 9: * Represents a single playable track in the music database. 10: * @author Jim Elliott (with help from Hibernate) 11: * 12:*/ 13:public class Track implements Serializable { 14: 15: /** identifier field */ 16: private Integer id; 17: 18: /** persistent field */ 19: private String title; 20: 21: /** persistent field */ 22: private String filePath; 23: 24: /** nullable persistent field */ 25: private Date playTime; 26: 27: /** nullable persistent field */ 28: private Date added; 29: 30: /** persistent field */ 31: private short volume; 32: 33: /** full constructor */ 34: public Track(String title, String filePath, Date playTime, Date added, short volume) { 35: this.title = title; 36: this.filePath = filePath; 37: this.playTime = playTime; 38: this.added = added; 39: this.volume = volume; 40: } 41: 42: /** default constructor */ 43: public Track() { 44: } 45: 46: /** minimal constructor */ 47: public Track(String title, String filePath, short volume) { 48: this.title = title; 49: this.filePath = filePath; 50: this.volume = volume; 51: } 52: 53: public Integer getId() { 54: return this.id; 55: } 56: 57: protected void setId(Integer id) { 58: this.id = id; 59: } 60: 61: public String getTitle() { 62: return this.title; 63: } 64: 65: public void setTitle(String title) { 66: this.title = title; 67: } 68: 69: public String getFilePath() { 70: return this.filePath; 71: } 72: 73: public void setFilePath(String filePath) { 74: this.filePath = filePath; 75: } 76: 77: /** 78: * Playing time 79: */ 80: public Date getPlayTime() { 81: return this.playTime; 82: } 83: 84: public void setPlayTime(Date playTime) { 85: this.playTime = playTime; 86: } 87: 88: /** 89: * When the track was created 90: */ 91: public Date getAdded() { 92: return this.added; 93: } 94: 95: public void setAdded(Date added) { 96: this.added = added; 97: } 98: 99: /** 100: * How loud to play the track 101: */ 102: public short getVolume() { 103: return this.volume; 104: } 105: 106: public void setVolume(short volume) { 107: this.volume = volume; 108: } 109: 110: public String toString() { 111: return new ToStringBuilder(this) 112: .append("id", getId()) 113: .toString(); 114: } 115: 116:} |
Ahora generamos el esquema en la base de datos
digital@localhost:~/SourceExamples/SourceExamples/ch02>
ant schema Buildfile: build.xml prepare: compile: schema: BUILD SUCCESSFUL |
Podemos observar la implementación directamente en el DBMS
mysql> use hibernate Database changed mysql> show tables; +---------------------+ | Tables_in_hibernate | +---------------------+ | TRACK | +---------------------+ 1 row in set (0.00 sec) mysql> desc TRACK; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | TRACK_ID | int(11) | | PRI | NULL | auto_increment | | title | varchar(255) | | | | | | filePath | varchar(255) | | | | | | playTime | time | YES | | NULL | | | added | date | YES | | NULL | | | volume | smallint(6) | | | 0 | | +----------+--------------+------+-----+---------+----------------+ 6 rows in set (0.01 sec) |
Hasta el momento hemos generado un DTO y un esquema en la base de datos para almacenar la información de dicho objeto, a continuación de muestra un ejemplo de como almacenar esos datos con Hibernate.
Clase que crea 3 Tracks y los almacena en la base de datos.
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.Date; 8: 9:/** 10: * Create sample data, letting Hibernate persist it for us. 11: */ 12:public class CreateTest { 13: 14: public static void main(String args[]) throws Exception { 15: // Create a configuration based on the properties file we've put 16: // in the standard place. 17: Configuration config = new Configuration(); 18: 19: // Tell it about the classes we want mapped, taking advantage of 20: // the way we've named their mapping documents. 21: config.addClass(Track.class); 22: 23: // Get the session factory we can use for persistence 24: SessionFactory sessionFactory = config.buildSessionFactory(); 25: 26: // Ask for a session using the JDBC information we've configured 27: Session session = sessionFactory.openSession(); 28: Transaction tx = null; 29: try { 30: // Create some data and persist it 31: tx = session.beginTransaction(); 32: 33: Track track = new Track("Russian Trance", 34: "vol2/album610/track02.mp3", 35: Time.valueOf("00:03:30"), new Date(), 36: (short)0); 37: session.save(track); 38: 39: track = new Track("Video Killed the Radio Star", 40: "vol2/album611/track12.mp3", 41: Time.valueOf("00:03:49"), new Date(), 42: (short)0); 43: session.save(track); 44: 45: 46: track = new Track("Gravity's Angel", 47: "vol2/album175/track03.mp3", 48: Time.valueOf("00:06:06"), new Date(), 49: (short)0); 50: session.save(track); 51: 52: // We're done; make our changes permanent 53: tx.commit(); 54: 55: } catch (Exception e) { 56: if (tx != null) { 57: // Something went wrong; discard all partial changes 58: tx.rollback(); 59: } 60: throw e; 61: } finally { 62: // No matter what, close the session 63: session.close(); 64: } 65: 66: // Clean up after ourselves 67: sessionFactory.close(); 68: } 69:} |
Creación de los 3 objetos y su almacenamiento persistente.
digital@localhost:~/SourceExamples/SourceExamples/ch03>
ant ctest prepare: compile: ctest: BUILD SUCCESSFUL |
Podemos comprobar lo anterior directamente en MySQL
mysql> select * from TRACK; +----------+-----------------------------+---------------------------+----------+------------+--------+ | TRACK_ID | title | filePath | playTime | added | volume | +----------+-----------------------------+---------------------------+----------+------------+--------+ | 1 | Russian Trance | vol2/album610/track02.mp3 | 00:03:30 | 2005-02-15 | 0 | | 2 | Video Killed the Radio Star | vol2/album611/track12.mp3 | 00:03:49 | 2005-02-15 | 0 | | 3 | Gravity's Angel | vol2/album175/track03.mp3 | 00:06:06 | 2005-02-15 | 0 | +----------+-----------------------------+---------------------------+----------+------------+--------+ 3 rows in set (0.00 sec) |
Veamos ahora como hacer una búsqueda sobre esos objetos almacenados
Clase que realiza un query (especificado en el archivo xml)
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.*; 8: 9:/** 10: * Retrieve data as objects 11: */ 12:public class QueryTest { 13: 14: /** 15: * Retrieve any tracks that fit in the specified amount of time. 16: * 17: * @param length the maximum playing time for tracks to be returned. 18: * @param session the Hibernate session that can retrieve data. 19: * @return a list of {@link Track}s meeting the length restriction. 20: * @throws HibernateException if there is a problem. 21: */ 22: public static List tracksNoLongerThan(Time length, Session session) 23: throws HibernateException 24: { 25: Query query = session.getNamedQuery( 26: "com.oreilly.hh.tracksNoLongerThan"); 27: query.setTime("length", length); 28: return query.list(); 29: } 30: 31: /** 32: * Look up and print some tracks when invoked from the command line. 33: */ 34: public static void main(String args[]) throws Exception { 35: // Create a configuration based on the properties file we've put 36: // in the standard place. 37: Configuration config = new Configuration(); 38: 39: // Tell it about the classes we want mapped, taking advantage of 40: // the way we've named their mapping documents. 41: config.addClass(Track.class); 42: 43: // Get the session factory we can use for persistence 44: SessionFactory sessionFactory = config.buildSessionFactory(); 45: 46: // Ask for a session using the JDBC information we've configured 47: Session session = sessionFactory.openSession(); 48: try { 49: // Print the tracks that will fit in five minutes 50: List tracks = tracksNoLongerThan(Time.valueOf("00:05:00"), 51: session); 52: for (ListIterator iter = tracks.listIterator() ; 53: iter.hasNext() ; ) { 54: Track aTrack = (Track)iter.next(); 55: System.out.println("Track: \"" + aTrack.getTitle() + 56: "\", " + aTrack.getPlayTime()); 57: } 58: } finally { 59: // No matter what, close the session 60: session.close(); 61: } 62: 63: // Clean up after ourselves 64: sessionFactory.close(); 65: } 66:} |
Ejecutamos el query para obtener aquellos Tracks que cumplen el criterio de búsqueda
digital@localhost:~/SourceExamples/SourceExamples/ch03>
ant qtest Buildfile: build.xml prepare: compile: qtest: BUILD SUCCESSFUL |
Archivo Track.hbm.xml conteniendo el query utilizado en el ejemplo anterior
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: 7: <class name="com.oreilly.hh.Track" table="TRACK"> 8: <meta attribute="class-description"> 9: Represents a single playable track in the music database. 10: @author Jim Elliott (with help from Hibernate) 11: </meta> 12: 13: <id name="id" type="int" column="TRACK_ID"> 14: <meta attribute="scope-set">protected</meta> 15: <generator class="native"/> 16: </id> 17: 18: <property name="title" type="string" not-null="true"/> 19: 20: <property name="filePath" type="string" not-null="true"/> 21: 22: <property name="playTime" type="time"> 23: <meta attribute="field-description">Playing time</meta> 24: </property> 25: 26: <property name="added" type="date"> 27: <meta attribute="field-description">When the track was created</meta> 28: </property> 29: 30: <property name="volume" type="short" not-null="true"> 31: <meta attribute="field-description">How loud to play the track</meta> 32: </property> 33: 34: </class> 35: 36: <query name="com.oreilly.hh.tracksNoLongerThan"> 37: <![CDATA[ 38: from com.oreilly.hh.Track as track 39: where track.playTime <= :length 40: ]]> 41: </query> 42: 43:</hibernate-mapping> |
Ejemplo que incluye Colecciones y Asociaciones
Pensemos en que ahora la entidad Track no está sola, sino existe otra Artist que se relaciona de manera M-M con Track, formando la nueva entidad Track_Artists.
Así mismo pensemos que cada Track puede tener muchos comentarios, tenemos una entidad débil Comments que se relaciona de manera M-1 con Track.
Nuestro nuevo archivo que describe a Track quedaría de la siguiente manera:
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: 7: <class name="com.oreilly.hh.Track" table="TRACK"> 8: <meta attribute="class-description"> 9: Represents a single playable track in the music database. 10: @author Jim Elliott (with help from Hibernate) 11: </meta> 12: 13: <id name="id" type="int" column="TRACK_ID"> 14: <meta attribute="scope-set">protected</meta> 15: <generator class="native"/> 16: </id> 17: 18: <property name="title" type="string"> 19: <meta attribute="use-in-tostring">true</meta> 20: <column name="TITLE" not-null="true" index="TRACK_TITLE"/> 21: </property> 22: 23: <property name="filePath" type="string" not-null="true"/> 24: 25: <property name="playTime" type="time"> 26: <meta attribute="field-description">Playing time</meta> 27: </property> 28: 29: <set name="artists" table="TRACK_ARTISTS"> 30: <key column="TRACK_ID"/> 31: <many-to-many class="com.oreilly.hh.Artist" column="ARTIST_ID"/> 32: </set> 33: 34: <set name="comments" table="TRACK_COMMENTS"> 35: <key column="TRACK_ID"/> 36: <element column="COMMENT" type="string"/> 37: </set> 38: 39: <property name="added" type="date"> 40: <meta attribute="field-description">When the track was created</meta> 41: </property> 42: 43: <property name="volume" type="short" not-null="true"> 44: <meta attribute="field-description">How loud to play the track</meta> 45: </property> 46: 47: </class> 48: 49: <query name="com.oreilly.hh.tracksNoLongerThan"> 50: <![CDATA[ 51: from com.oreilly.hh.Track as track 52: where track.playTime <= :length 53: ]]> 54: </query> 55: 56:</hibernate-mapping> |
Y el archivo para describir al nuevo objeto Artist (Artist.hbm.xml) se muestra a continuación.
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: 7: <class name="com.oreilly.hh.Artist" table="ARTIST"> 8: <meta attribute="class-description"> 9: Represents an artist who is associated with a track or album. 10: @author Jim Elliott (with help from Hibernate) 11: </meta> 12: 13: <id name="id" type="int" column="ARTIST_ID"> 14: <meta attribute="scope-set">protected</meta> 15: <generator class="native"/> 16: </id> 17: 18: <property name="name" type="string"> 19: <meta attribute="use-in-tostring">true</meta> 20: <column name="NAME" not-null="true" unique="true" index="ARTIST_NAME"/> 21: </property> 22: 23: <set name="tracks" table="TRACK_ARTISTS" inverse="true"> 24: <meta attribute="field-description">Tracks by this artist</meta> 25: <key column="ARTIST_ID"/> 26: <many-to-many class="com.oreilly.hh.Track" column="TRACK_ID"/> 27: </set> 28: 29: </class> 30: 31: <query name="com.oreilly.hh.artistByName"> 32: <![CDATA[ 33: from com.oreilly.hh.Artist as artist 34: where upper(artist.name) = upper(:name) 35: ]]> 36: </query> 37: 38:</hibernate-mapping> |
Generamos el codigo java correspondiente a cada objeto.
digital@localhost:~/SourceExamples/SourceExamples/ch04>
ant codegen Buildfile: build.xml prepare: codegen: BUILD SUCCESSFUL |
Nueva Clase Track.java que contempla las relaciones con Artist y Comments
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import java.util.Date; 5:import java.util.Set; 6:import org.apache.commons.lang.builder.ToStringBuilder; 7: 8: 9:/** 10: * Represents a single playable track in the music database. 11: * @author Jim Elliott (with help from Hibernate) 12: * 13:*/ 14:public class Track implements Serializable { 15: 16: /** identifier field */ 17: private Integer id; 18: 19: /** nullable persistent field */ 20: private String title; 21: 22: /** persistent field */ 23: private String filePath; 24: 25: /** nullable persistent field */ 26: private Date playTime; 27: 28: /** nullable persistent field */ 29: private Date added; 30: 31: /** persistent field */ 32: private short volume; 33: 34: /** persistent field */ 35: private Set artists; 36: 37: /** persistent field */ 38: private Set comments; 39: 40: /** full constructor */ 41: public Track(String title, String filePath, Date playTime, Date added, short volume, Set artists, Set comments) { 42: this.title = title; 43: this.filePath = filePath; 44: this.playTime = playTime; 45: this.added = added; 46: this.volume = volume; 47: this.artists = artists; 48: this.comments = comments; 49: } 50: 51: /** default constructor */ 52: public Track() { 53: } 54: 55: /** minimal constructor */ 56: public Track(String filePath, short volume, Set artists, Set comments) { 57: this.filePath = filePath; 58: this.volume = volume; 59: this.artists = artists; 60: this.comments = comments; 61: } 62: 63: public Integer getId() { 64: return this.id; 65: } 66: 67: protected void setId(Integer id) { 68: this.id = id; 69: } 70: 71: public String getTitle() { 72: return this.title; 73: } 74: 75: public void setTitle(String title) { 76: this.title = title; 77: } 78: 79: public String getFilePath() { 80: return this.filePath; 81: } 82: 83: public void setFilePath(String filePath) { 84: this.filePath = filePath; 85: } 86: 87: /** 88: * Playing time 89: */ 90: public Date getPlayTime() { 91: return this.playTime; 92: } 93: 94: public void setPlayTime(Date playTime) { 95: this.playTime = playTime; 96: } 97: 98: /** 99: * When the track was created 100: */ 101: public Date getAdded() { 102: return this.added; 103: } 104: 105: public void setAdded(Date added) { 106: this.added = added; 107: } 108: 109: /** 110: * How loud to play the track 111: */ 112: public short getVolume() { 113: return this.volume; 114: } 115: 116: public void setVolume(short volume) { 117: this.volume = volume; 118: } 119: 120: public Set getArtists() { 121: return this.artists; 122: } 123: 124: public void setArtists(Set artists) { 125: this.artists = artists; 126: } 127: 128: public Set getComments() { 129: return this.comments; 130: } 131: 132: public void setComments(Set comments) { 133: this.comments = comments; 134: } 135: 136: public String toString() { 137: return new ToStringBuilder(this) 138: .append("id", getId()) 139: .append("title", getTitle()) 140: .toString(); 141: } 142: 143:} |
Clase Artist.java
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import java.util.Set; 5:import org.apache.commons.lang.builder.ToStringBuilder; 6: 7: 8:/** 9: * Represents an artist who is associated with a track or album. 10: * @author Jim Elliott (with help from Hibernate) 11: * 12:*/ 13:public class Artist implements Serializable { 14: 15: /** identifier field */ 16: private Integer id; 17: 18: /** nullable persistent field */ 19: private String name; 20: 21: /** persistent field */ 22: private Set tracks; 23: 24: /** full constructor */ 25: public Artist(String name, Set tracks) { 26: this.name = name; 27: this.tracks = tracks; 28: } 29: 30: /** default constructor */ 31: public Artist() { 32: } 33: 34: /** minimal constructor */ 35: public Artist(Set tracks) { 36: this.tracks = tracks; 37: } 38: 39: public Integer getId() { 40: return this.id; 41: } 42: 43: protected void setId(Integer id) { 44: this.id = id; 45: } 46: 47: public String getName() { 48: return this.name; 49: } 50: 51: public void setName(String name) { 52: this.name = name; 53: } 54: 55: /** 56: * Tracks by this artist 57: */ 58: public Set getTracks() { 59: return this.tracks; 60: } 61: 62: public void setTracks(Set tracks) { 63: this.tracks = tracks; 64: } 65: 66: public String toString() { 67: return new ToStringBuilder(this) 68: .append("id", getId()) 69: .append("name", getName()) 70: .toString(); 71: } 72: 73:} |
Nuevamente creamos el esquema en la base de datos para reflejar las relaciones involucradas.
digital@localhost:~/SourceExamples/SourceExamples/ch04>
ant schema Buildfile: build.xml prepare: compile: schema: BUILD SUCCESSFUL |
Lo verificamos directamente en MySQL
mysql> show tables; +---------------------+ | Tables_in_hibernate | +---------------------+ | ARTIST | | TRACK | | TRACK_ARTISTS | | TRACK_COMMENTS | +---------------------+ 4 rows in set (0.00 sec) mysql> desc ARTIST; +-----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+----------------+ | ARTIST_ID | int(11) | | PRI | NULL | auto_increment | | NAME | varchar(255) | | UNI | | | +-----------+--------------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql> desc TRACK; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | TRACK_ID | int(11) | | PRI | NULL | auto_increment | | TITLE | varchar(255) | | MUL | | | | filePath | varchar(255) | | | | | | playTime | time | YES | | NULL | | | added | date | YES | | NULL | | | volume | smallint(6) | | | 0 | | +----------+--------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec) mysql> desc TRACK_ARTISTS; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | ARTIST_ID | int(11) | | PRI | 0 | | | TRACK_ID | int(11) | | PRI | 0 | | +-----------+---------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> desc TRACK_COMMENTS; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | TRACK_ID | int(11) | | MUL | 0 | | | COMMENT | varchar(255) | YES | | NULL | | +----------+--------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> select * from ARTIST; mysql> select * from TRACK; Empty set (0.00 sec) mysql> select * from TRACK_ARTISTS; Empty set (0.00 sec) mysql> select * from TRACK_COMMENTS; Empty set (0.00 sec) |
Veamos ahora el ejemplo de cómo crear un objeto (con sus respectivas relaciones) y hacerlo persistente en el DBMS
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.*; 8: 9:/** 10: * Create more sample data, letting Hibernate persist it for us. 11: */ 12:public class CreateTest { 13: 14: /** 15: * Look up an artist record given a name. 16: * @param name the name of the artist desired. 17: * @param create controls whether a new record should be created if 18: * the specified artist is not yet in the database. 19: * @param session the Hibernate session that can retrieve data 20: * @return the artist with the specified name, or <code>null</code> if no 21: * such artist exists and <code>create</code> is <code>false</code>. 22: * @throws HibernateException if there is a problem. 23: */ 24: public static Artist getArtist(String name, boolean create, 25: Session session) 26: throws HibernateException 27: { 28: Query query = session.getNamedQuery( 29: "com.oreilly.hh.artistByName"); 30: query.setString("name", name); 31: Artist found = (Artist)query.uniqueResult(); 32: if (found == null && create) { 33: found = new Artist(name, new HashSet()); 34: session.save(found); 35: } 36: return found; 37: } 38: 39: /** 40: * Utility method to associate an artist with a track 41: */ 42: private static void addTrackArtist(Track track, Artist artist) { 43: track.getArtists().add(artist); 44: } 45: 46: public static void main(String args[]) throws Exception { 47: // Create a configuration based on the properties file we've put 48: // in the standard place. 49: Configuration config = new Configuration(); 50: 51: // Tell it about the classes we want mapped, taking advantage of 52: // the way we've named their mapping documents. 53: config.addClass(Track.class).addClass(Artist.class); 54: 55: // Get the session factory we can use for persistence 56: SessionFactory sessionFactory = config.buildSessionFactory(); 57: 58: // Ask for a session using the JDBC information we've configured 59: Session session = sessionFactory.openSession(); 60: Transaction tx = null; 61: try { 62: // Create some data and persist it 63: tx = session.beginTransaction(); 64: 65: Track track = new Track("Russian Trance", 66: "vol2/album610/track02.mp3", 67: Time.valueOf("00:03:30"), new Date(), 68: (short)0, new HashSet(), new HashSet()); 69: addTrackArtist(track, getArtist("PPK", true, session)); 70: session.save(track); 71: 72: track = new Track("Video Killed the Radio Star", 73: "vol2/album611/track12.mp3", 74: Time.valueOf("00:03:49"), new Date(), 75: (short)0, new HashSet(), new HashSet()); 76: addTrackArtist(track, getArtist("The Buggles", true, session)); 77: session.save(track); 78: 79: 80: track = new Track("Gravity's Angel", 81: "vol2/album175/track03.mp3", 82: Time.valueOf("00:06:06"), new Date(), 83: (short)0, new HashSet(), new HashSet()); 84: addTrackArtist(track, getArtist("Laurie Anderson", true, session)); 85: session.save(track); 86: 87: track = new Track("Adagio for Strings (Ferry Corsten Remix)", 88: "vol2/album972/track01.mp3", 89: Time.valueOf("00:06:35"), new Date(), 90: (short)0, new HashSet(), new HashSet()); 91: addTrackArtist(track, getArtist("William Orbit", true, session)); 92: addTrackArtist(track, getArtist("Ferry Corsten", true, session)); 93: addTrackArtist(track, getArtist("Samuel Barber", true, session)); 94: session.save(track); 95: 96: track = new Track("Adagio for Strings (ATB Remix)", 97: "vol2/album972/track02.mp3", 98: Time.valueOf("00:07:39"), new Date(), 99: (short)0, new HashSet(), new HashSet()); 100: addTrackArtist(track, getArtist("William Orbit", true, session)); 101: addTrackArtist(track, getArtist("ATB", true, session)); 102: addTrackArtist(track, getArtist("Samuel Barber", true, session)); 103: session.save(track); 104: 105: track = new Track("The World '99", 106: "vol2/singles/pvw99.mp3", 107: Time.valueOf("00:07:05"), new Date(), 108: (short)0, new HashSet(), new HashSet()); 109: addTrackArtist(track, getArtist("Pulp Victim", true, session)); 110: addTrackArtist(track, getArtist("Ferry Corsten", true, session)); 111: session.save(track); 112: 113: track = new Track("Test Tone 1", 114: "vol2/singles/test01.mp3", 115: Time.valueOf("00:00:10"), new Date(), 116: (short)0, new HashSet(), new HashSet()); 117: track.getComments().add("Pink noise to test equalization"); 118: session.save(track); 119: 120: // We're done; make our changes permanent 121: tx.commit(); 122: 123: } catch (Exception e) { 124: if (tx != null) { 125: // Something went wrong; discard all partial changes 126: tx.rollback(); 127: } 128: throw e; 129: } finally { 130: // No matter what, close the session 131: session.close(); 132: } 133: 134: // Clean up after ourselves 135: sessionFactory.close(); 136: } 137:} |
Lo ejecutamos para poder apreciar el funcionamiento de la inserción
digital@localhost:~/SourceExamples/SourceExamples/ch04>
ant ctest Buildfile: build.xml prepare: compile: ctest: BUILD SUCCESSFUL |
En la base de datos podemos confirmar que efectivamente los objetos fueron almacenados
mysql> select * from ARTIST; +-----------+-----------------+ | ARTIST_ID | NAME | +-----------+-----------------+ | 1 | PPK | | 2 | The Buggles | | 3 | Laurie Anderson | | 4 | William Orbit | | 5 | Ferry Corsten | | 6 | Samuel Barber | | 7 | ATB | | 8 | Pulp Victim | +-----------+-----------------+ 8 rows in set (0.00 sec) mysql> select * from TRACK; +----------+------------------------------------------+---------------------------+----------+------------+--------+ | TRACK_ID | TITLE | filePath | playTime | added | volume | +----------+------------------------------------------+---------------------------+----------+------------+--------+ | 1 | Russian Trance | vol2/album610/track02.mp3 | 00:03:30 | 2005-02-15 | 0 | | 2 | Video Killed the Radio Star | vol2/album611/track12.mp3 | 00:03:49 | 2005-02-15 | 0 | | 3 | Gravity's Angel | vol2/album175/track03.mp3 | 00:06:06 | 2005-02-15 | 0 | | 4 | Adagio for Strings (Ferry Corsten Remix) | vol2/album972/track01.mp3 | 00:06:35 | 2005-02-15 | 0 | | 5 | Adagio for Strings (ATB Remix) | vol2/album972/track02.mp3 | 00:07:39 | 2005-02-15 | 0 | | 6 | The World '99 | vol2/singles/pvw99.mp3 | 00:07:05 | 2005-02-15 | 0 | | 7 | Test Tone 1 | vol2/singles/test01.mp3 | 00:00:10 | 2005-02-15 | 0 | +----------+------------------------------------------+---------------------------+----------+------------+--------+ 7 rows in set (0.00 sec) mysql> select * from TRACK_ARTISTS; +-----------+----------+ | ARTIST_ID | TRACK_ID | +-----------+----------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 4 | | 6 | 4 | | 4 | 5 | | 6 | 5 | | 7 | 5 | | 5 | 6 | | 8 | 6 | +-----------+----------+ 11 rows in set (0.00 sec) mysql> select * from TRACK_COMMENTS; +----------+---------------------------------+ | TRACK_ID | COMMENT | +----------+---------------------------------+ | 7 | Pink noise to test equalization | +----------+---------------------------------+ 1 row in set (0.00 sec) |
Finalmente hagamos una búsqueda para recuperar los Tracks que cumplan con algun criterio particular.
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.*; 8: 9:/** 10: * Retrieve data as objects 11: */ 12:public class QueryTest { 13: 14: /** 15: * Retrieve any tracks that fit in the specified amount of time. 16: * 17: * @param length the maximum playing time for tracks to be returned. 18: * @param session the Hibernate session that can retrieve data. 19: * @return a list of {@link Track}s meeting the length restriction. 20: * @throws HibernateException if there is a problem. 21: */ 22: public static List tracksNoLongerThan(Time length, Session session) 23: throws HibernateException 24: { 25: Query query = session.getNamedQuery( 26: "com.oreilly.hh.tracksNoLongerThan"); 27: query.setTime("length", length); 28: return query.list(); 29: } 30: 31: /** 32: * Build a parenthetical, comma-separated list of artist names. 33: * @param artists the artists whose names are to be displayed. 34: * @return formatted list, or an empty string if the set was empty. 35: */ 36: public static String listArtistNames(Set artists) { 37: StringBuffer result = new StringBuffer(); 38: for (Iterator iter = artists.iterator(); iter.hasNext(); ) { 39: Artist artist = (Artist)iter.next(); 40: result.append((result.length() == 0) ? "(" : ", "); 41: result.append(artist.getName()); 42: } 43: if (result.length() > 0) { 44: result.append(") "); 45: } 46: return result.toString(); 47: } 48: 49: /** 50: * Look up and print some tracks when invoked from the command line. 51: */ 52: public static void main(String args[]) throws Exception { 53: // Create a configuration based on the properties file we've put 54: // in the standard place. 55: Configuration config = new Configuration(); 56: 57: // Tell it about the classes we want mapped, taking advantage of 58: // the way we've named their mapping documents. 59: config.addClass(Track.class).addClass(Artist.class); 60: 61: // Get the session factory we can use for persistence 62: SessionFactory sessionFactory = config.buildSessionFactory(); 63: 64: // Ask for a session using the JDBC information we've configured 65: Session session = sessionFactory.openSession(); 66: try { 67: // Print the tracks that will fit in seven minutes 68: List tracks = tracksNoLongerThan(Time.valueOf("00:07:00"), 69: session); 70: for (ListIterator iter = tracks.listIterator() ; 71: iter.hasNext() ; ) { 72: Track aTrack = (Track)iter.next(); 73: System.out.println("Track: \"" + aTrack.getTitle() + "\" " + 74: listArtistNames(aTrack.getArtists()) + 75: aTrack.getPlayTime()); 76: for (Iterator comIter = aTrack.getComments().iterator() ; 77: comIter.hasNext() ; ) { 78: System.out.println(" Comment: " + comIter.next()); 79: } 80: } 81: } finally { 82: // No matter what, close the session 83: session.close(); 84: } 85: 86: // Clean up after ourselves 87: sessionFactory.close(); 88: } 89:} |
Ejecutamos la consulta sobre la base de datos con Hibernate.
digital@localhost:~/SourceExamples/SourceExamples/ch04>
ant qtest Buildfile: build.xml prepare: compile: qtest: BUILD SUCCESSFUL |
Asociaciones más ricas.
Supongamos que se quiere implementar el siguiente modelo:
Nuevamente nuestro archivo que describe a Track sería:
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: 7: <class name="com.oreilly.hh.Track" table="TRACK"> 8: <meta attribute="class-description"> 9: Represents a single playable track in the music database. 10: @author Jim Elliott (with help from Hibernate) 11: </meta> 12: 13: <id name="id" type="int" column="TRACK_ID"> 14: <meta attribute="scope-set">protected</meta> 15: <generator class="native"/> 16: </id> 17: 18: <property name="title" type="string"> 19: <meta attribute="use-in-tostring">true</meta> 20: <column name="TITLE" not-null="true" index="TRACK_TITLE"/> 21: </property> 22: 23: <property name="filePath" type="string" not-null="true"/> 24: 25: <property name="playTime" type="time"> 26: <meta attribute="field-description">Playing time</meta> 27: </property> 28: 29: <set name="artists" table="TRACK_ARTISTS"> 30: <key column="TRACK_ID"/> 31: <many-to-many class="com.oreilly.hh.Artist" column="ARTIST_ID"/> 32: </set> 33: 34: <set name="comments" table="TRACK_COMMENTS"> 35: <key column="TRACK_ID"/> 36: <element column="COMMENT" type="string"/> 37: </set> 38: 39: <property name="added" type="date"> 40: <meta attribute="field-description">When the track was created</meta> 41: </property> 42: 43: <property name="volume" type="short" not-null="true"> 44: <meta attribute="field-description">How loud to play the track</meta> 45: </property> 46: 47: </class> 48: 49: <query name="com.oreilly.hh.tracksNoLongerThan"> 50: <![CDATA[ 51: from com.oreilly.hh.Track as track 52: where track.playTime <= :length 53: ]]> 54: </query> 55: 56:</hibernate-mapping> |
La descripción del objeto Artist:
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: 7: <class name="com.oreilly.hh.Artist" table="ARTIST"> 8: <meta attribute="class-description"> 9: Represents an artist who is associated with a track or album. 10: @author Jim Elliott (with help from Hibernate) 11: </meta> 12: 13: <id name="id" type="int" column="ARTIST_ID"> 14: <meta attribute="scope-set">protected</meta> 15: <generator class="native"/> 16: </id> 17: 18: <property name="name" type="string"> 19: <meta attribute="use-in-tostring">true</meta> 20: <column name="NAME" not-null="true" unique="true" index="ARTIST_NAME"/> 21: </property> 22: 23: <set name="tracks" table="TRACK_ARTISTS" inverse="true"> 24: <meta attribute="field-description">Tracks by this artist</meta> 25: <key column="ARTIST_ID"/> 26: <many-to-many class="com.oreilly.hh.Track" column="TRACK_ID"/> 27: </set> 28: 29: <many-to-one name="actualArtist" class="com.oreilly.hh.Artist"> 30: <meta attribute="use-in-tostring">true</meta> 31: </many-to-one> 32: 33: </class> 34: 35: <query name="com.oreilly.hh.artistByName"> 36: <![CDATA[ 37: from com.oreilly.hh.Artist as artist 38: where upper(artist.name) = upper(:name) 39: ]]> 40: </query> 41: 42:</hibernate-mapping> |
El nuevo objeto de nuestro modelo Album:
1:<?xml version="1.0"?> 2:<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 3: "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 4: 5:<hibernate-mapping> 6: <class name="com.oreilly.hh.Album" table="ALBUM"> 7: <meta attribute="class-description"> 8: Represents an album in the music database, an organized list of tracks. 9: @author Jim Elliott (with help from Hibernate) 10: </meta> 11: 12: <id name="id" type="int" column="ALBUM_ID"> 13: <meta attribute="scope-set">protected</meta> 14: <generator class="native"/> 15: </id> 16: 17: <property name="title" type="string"> 18: <meta attribute="use-in-tostring">true</meta> 19: <column name="TITLE" not-null="true" index="ALBUM_TITLE"/> 20: </property> 21: 22: <property name="numDiscs" type="integer" not-null="true"/> 23: 24: <set name="artists" table="ALBUM_ARTISTS"> 25: <key column="ALBUM_ID"/> 26: <many-to-many class="com.oreilly.hh.Artist" column="ARTIST_ID"/> 27: </set> 28: 29: <set name="comments" table="ALBUM_COMMENTS"> 30: <key column="ALBUM_ID"/> 31: <element column="COMMENT" type="string"/> 32: </set> 33: 34: <list name="tracks" table="ALBUM_TRACKS" cascade="all"> 35: <meta attribute="use-in-tostring">true</meta> 36: <key column="ALBUM_ID"/> 37: <index column="POS"/> 38: <composite-element class="com.oreilly.hh.AlbumTrack"> 39: <many-to-one name="track" class="com.oreilly.hh.Track" cascade="all"> 40: <meta attribute="use-in-tostring">true</meta> 41: <column name="TRACK_ID"/> 42: </many-to-one> 43: <property name="disc" type="integer" not-null="true"/> 44: <property name="positionOnDisc" type="integer" not-null="true"/> 45: </composite-element> 46: </list> 47: 48: <property name="added" type="date"> 49: <meta attribute="field-description">When the album was created</meta> 50: </property> 51: 52: </class> 53:</hibernate-mapping> |
Necesitamos nuevamente generar los códigos Java:
digital@localhost:~/SourceExamples/SourceExamples/ch05>
ant codegen Buildfile: build.xml prepare: codegen: BUILD SUCCESSFUL |
De manera que la clase Track.java resultante sería:
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import java.util.Date; 5:import java.util.Set; 6:import org.apache.commons.lang.builder.ToStringBuilder; 7: 8: 9:/** 10: * Represents a single playable track in the music database. 11: * @author Jim Elliott (with help from Hibernate) 12: * 13:*/ 14:public class Track implements Serializable { 15: 16: /** identifier field */ 17: private Integer id; 18: 19: /** nullable persistent field */ 20: private String title; 21: 22: /** persistent field */ 23: private String filePath; 24: 25: /** nullable persistent field */ 26: private Date playTime; 27: 28: /** nullable persistent field */ 29: private Date added; 30: 31: /** persistent field */ 32: private short volume; 33: 34: /** persistent field */ 35: private Set artists; 36: 37: /** persistent field */ 38: private Set comments; 39: 40: /** full constructor */ 41: public Track(String title, String filePath, Date playTime, Date added, short volume, Set artists, Set comments) { 42: this.title = title; 43: this.filePath = filePath; 44: this.playTime = playTime; 45: this.added = added; 46: this.volume = volume; 47: this.artists = artists; 48: this.comments = comments; 49: } 50: 51: /** default constructor */ 52: public Track() { 53: } 54: 55: /** minimal constructor */ 56: public Track(String filePath, short volume, Set artists, Set comments) { 57: this.filePath = filePath; 58: this.volume = volume; 59: this.artists = artists; 60: this.comments = comments; 61: } 62: 63: public Integer getId() { 64: return this.id; 65: } 66: 67: protected void setId(Integer id) { 68: this.id = id; 69: } 70: 71: public String getTitle() { 72: return this.title; 73: } 74: 75: public void setTitle(String title) { 76: this.title = title; 77: } 78: 79: public String getFilePath() { 80: return this.filePath; 81: } 82: 83: public void setFilePath(String filePath) { 84: this.filePath = filePath; 85: } 86: 87: /** 88: * Playing time 89: */ 90: public Date getPlayTime() { 91: return this.playTime; 92: } 93: 94: public void setPlayTime(Date playTime) { 95: this.playTime = playTime; 96: } 97: 98: /** 99: * When the track was created 100: */ 101: public Date getAdded() { 102: return this.added; 103: } 104: 105: public void setAdded(Date added) { 106: this.added = added; 107: } 108: 109: /** 110: * How loud to play the track 111: */ 112: public short getVolume() { 113: return this.volume; 114: } 115: 116: public void setVolume(short volume) { 117: this.volume = volume; 118: } 119: 120: public Set getArtists() { 121: return this.artists; 122: } 123: 124: public void setArtists(Set artists) { 125: this.artists = artists; 126: } 127: 128: public Set getComments() { 129: return this.comments; 130: } 131: 132: public void setComments(Set comments) { 133: this.comments = comments; 134: } 135: 136: public String toString() { 137: return new ToStringBuilder(this) 138: .append("id", getId()) 139: .append("title", getTitle()) 140: .toString(); 141: } 142: 143:} |
Así mismo la clase Artist.java:
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import java.util.Set; 5:import org.apache.commons.lang.builder.ToStringBuilder; 6: 7: 8:/** 9: * Represents an artist who is associated with a track or album. 10: * @author Jim Elliott (with help from Hibernate) 11: * 12:*/ 13:public class Artist implements Serializable { 14: 15: /** identifier field */ 16: private Integer id; 17: 18: /** nullable persistent field */ 19: private String name; 20: 21: /** nullable persistent field */ 22: private com.oreilly.hh.Artist actualArtist; 23: 24: /** persistent field */ 25: private Set tracks; 26: 27: /** full constructor */ 28: public Artist(String name, com.oreilly.hh.Artist actualArtist, Set tracks) { 29: this.name = name; 30: this.actualArtist = actualArtist; 31: this.tracks = tracks; 32: } 33: 34: /** default constructor */ 35: public Artist() { 36: } 37: 38: /** minimal constructor */ 39: public Artist(Set tracks) { 40: this.tracks = tracks; 41: } 42: 43: public Integer getId() { 44: return this.id; 45: } 46: 47: protected void setId(Integer id) { 48: this.id = id; 49: } 50: 51: public String getName() { 52: return this.name; 53: } 54: 55: public void setName(String name) { 56: this.name = name; 57: } 58: 59: public com.oreilly.hh.Artist getActualArtist() { 60: return this.actualArtist; 61: } 62: 63: public void setActualArtist(com.oreilly.hh.Artist actualArtist) { 64: this.actualArtist = actualArtist; 65: } 66: 67: /** 68: * Tracks by this artist 69: */ 70: public Set getTracks() { 71: return this.tracks; 72: } 73: 74: public void setTracks(Set tracks) { 75: this.tracks = tracks; 76: } 77: 78: public String toString() { 79: return new ToStringBuilder(this) 80: .append("id", getId()) 81: .append("name", getName()) 82: .append("actualArtist", getActualArtist()) 83: .toString(); 84: } 85: 86:} |
La clase Album.java
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import java.util.Date; 5:import java.util.List; 6:import java.util.Set; 7:import org.apache.commons.lang.builder.ToStringBuilder; 8: 9: 10:/** 11: * Represents an album in the music database, an organized list of tracks. 12: * @author Jim Elliott (with help from Hibernate) 13: * 14:*/ 15:public class Album implements Serializable { 16: 17: /** identifier field */ 18: private Integer id; 19: 20: /** nullable persistent field */ 21: private String title; 22: 23: /** persistent field */ 24: private int numDiscs; 25: 26: /** nullable persistent field */ 27: private Date added; 28: 29: /** persistent field */ 30: private List tracks; 31: 32: /** persistent field */ 33: private Set artists; 34: 35: /** persistent field */ 36: private Set comments; 37: 38: /** full constructor */ 39: public Album(String title, int numDiscs, Date added, List tracks, Set artists, Set comments) { 40: this.title = title; 41: this.numDiscs = numDiscs; 42: this.added = added; 43: this.tracks = tracks; 44: this.artists = artists; 45: this.comments = comments; 46: } 47: 48: /** default constructor */ 49: public Album() { 50: } 51: 52: /** minimal constructor */ 53: public Album(int numDiscs, List tracks, Set artists, Set comments) { 54: this.numDiscs = numDiscs; 55: this.tracks = tracks; 56: this.artists = artists; 57: this.comments = comments; 58: } 59: 60: public Integer getId() { 61: return this.id; 62: } 63: 64: protected void setId(Integer id) { 65: this.id = id; 66: } 67: 68: public String getTitle() { 69: return this.title; 70: } 71: 72: public void setTitle(String title) { 73: this.title = title; 74: } 75: 76: public int getNumDiscs() { 77: return this.numDiscs; 78: } 79: 80: public void setNumDiscs(int numDiscs) { 81: this.numDiscs = numDiscs; 82: } 83: 84: /** 85: * When the album was created 86: */ 87: public Date getAdded() { 88: return this.added; 89: } 90: 91: public void setAdded(Date added) { 92: this.added = added; 93: } 94: 95: public List getTracks() { 96: return this.tracks; 97: } 98: 99: public void setTracks(List tracks) { 100: this.tracks = tracks; 101: } 102: 103: public Set getArtists() { 104: return this.artists; 105: } 106: 107: public void setArtists(Set artists) { 108: this.artists = artists; 109: } 110: 111: public Set getComments() { 112: return this.comments; 113: } 114: 115: public void setComments(Set comments) { 116: this.comments = comments; 117: } 118: 119: public String toString() { 120: return new ToStringBuilder(this) 121: .append("id", getId()) 122: .append("title", getTitle()) 123: .append("tracks", getTracks()) 124: .toString(); 125: } 126: 127:} |
La nueva clase creada a partir de la relación Track-Album, AlbumTrack.java:
1:package com.oreilly.hh; 2: 3:import java.io.Serializable; 4:import org.apache.commons.lang.builder.ToStringBuilder; 5: 6: 7:/** 8: * Represents an album in the music database, an organized list of tracks. 9: * @author Jim Elliott (with help from Hibernate) 10: * 11:*/ 12:public class AlbumTrack implements Serializable { 13: 14: /** persistent field */ 15: private int disc; 16: 17: /** persistent field */ 18: private int positionOnDisc; 19: 20: /** nullable persistent field */ 21: private com.oreilly.hh.Track track; 22: 23: /** full constructor */ 24: public AlbumTrack(int disc, int positionOnDisc, com.oreilly.hh.Track track) { 25: this.disc = disc; 26: this.positionOnDisc = positionOnDisc; 27: this.track = track; 28: } 29: 30: /** default constructor */ 31: public AlbumTrack() { 32: } 33: 34: /** minimal constructor */ 35: public AlbumTrack(int disc, int positionOnDisc) { 36: this.disc = disc; 37: this.positionOnDisc = positionOnDisc; 38: } 39: 40: public int getDisc() { 41: return this.disc; 42: } 43: 44: public void setDisc(int disc) { 45: this.disc = disc; 46: } 47: 48: public int getPositionOnDisc() { 49: return this.positionOnDisc; 50: } 51: 52: public void setPositionOnDisc(int positionOnDisc) { 53: this.positionOnDisc = positionOnDisc; 54: } 55: 56: public com.oreilly.hh.Track getTrack() { 57: return this.track; 58: } 59: 60: public void setTrack(com.oreilly.hh.Track track) { 61: this.track = track; 62: } 63: 64: public String toString() { 65: return new ToStringBuilder(this) 66: .append("track", getTrack()) 67: .toString(); 68: } 69: 70:} |
Nuevamente generamos el esquema en la base de datos
digital@localhost:~/SourceExamples/SourceExamples/ch05>
ant schema Buildfile: build.xml prepare: compile: schema: BUILD SUCCESSFUL |
Verificamos directamente en el DBMS la creación del esquema.
mysql> use hibernate; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +---------------------+ | Tables_in_hibernate | +---------------------+ | ARTIST | | TRACK | | TRACK_ARTISTS | | TRACK_COMMENTS | +---------------------+ 4 rows in set (0.00 sec) mysql> show tables; +---------------------+ | Tables_in_hibernate | +---------------------+ | ALBUM | | ALBUM_ARTISTS | | ALBUM_COMMENTS | | ALBUM_TRACKS | | ARTIST | | TRACK | | TRACK_ARTISTS | | TRACK_COMMENTS | +---------------------+ 8 rows in set (0.00 sec) mysql> desc ALBUM; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | ALBUM_ID | int(11) | | PRI | NULL | auto_increment | | TITLE | varchar(255) | | MUL | | | | numDiscs | int(11) | | | 0 | | | added | date | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 4 rows in set (0.01 sec) mysql> desc ALBUM_ARTISTS; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | ALBUM_ID | int(11) | | PRI | 0 | | | ARTIST_ID | int(11) | | PRI | 0 | | +-----------+---------+------+-----+---------+-------+ 2 rows in set (0.01 sec) mysql> desc ALBUM_COMMENTS; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | ALBUM_ID | int(11) | | MUL | 0 | | | COMMENT | varchar(255) | YES | | NULL | | +----------+--------------+------+-----+---------+-------+ 2 rows in set (0.01 sec) mysql> desc ALBUM_TRACKS; +----------------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+---------+------+-----+---------+-------+ | ALBUM_ID | int(11) | | PRI | 0 | | | TRACK_ID | int(11) | YES | MUL | NULL | | | disc | int(11) | | | 0 | | | positionOnDisc | int(11) | | | 0 | | | POS | int(11) | | PRI | 0 | | +----------------+---------+------+-----+---------+-------+ 5 rows in set (0.00 sec) mysql> desc ARTIST; +--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | ARTIST_ID | int(11) | | PRI | NULL | auto_increment | | NAME | varchar(255) | | UNI | | | | actualArtist | int(11) | YES | MUL | NULL | | +--------------+--------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec) mysql> desc TRACK; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | TRACK_ID | int(11) | | PRI | NULL | auto_increment | | TITLE | varchar(255) | | MUL | | | | filePath | varchar(255) | | | | | | playTime | time | YES | | NULL | | | added | date | YES | | NULL | | | volume | smallint(6) | | | 0 | | +----------+--------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec) mysql> desc TRACK_ARTISTS; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | ARTIST_ID | int(11) | | PRI | 0 | | | TRACK_ID | int(11) | | PRI | 0 | | +-----------+---------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> desc TRACK_COMMENTS; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | TRACK_ID | int(11) | | MUL | 0 | | | COMMENT | varchar(255) | YES | | NULL | | +----------+--------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> show tables; +---------------------+ | Tables_in_hibernate | +---------------------+ | ALBUM | | ALBUM_ARTISTS | | ALBUM_COMMENTS | | ALBUM_TRACKS | | ARTIST | | TRACK | | TRACK_ARTISTS | | TRACK_COMMENTS | +---------------------+ 8 rows in set (0.00 sec) mysql> select * from ALBUM; Empty set (0.01 sec) mysql> select * from ALBUM_ARTISTS; Empty set (0.00 sec) mysql> select * from ALBUM_COMMENTS; Empty set (0.00 sec) mysql> select * from ALBUM_TRACKS; Empty set (0.00 sec) mysql> select * from ARTIST; Empty set (0.01 sec) mysql> select * from TRACK; Empty set (0.01 sec) mysql> select * from TRACK_ARTISTS; Empty set (0.00 sec) mysql> select * from TRACK_COMMENTS; Empty set (0.00 sec) mysql> select * from ALBUM; Empty set (0.00 sec) |
A continuación se presenta el código ejemplo para agregar información a nuestro nuevo modelo de datos.
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.*; 8: 9:/** 10: * Create more sample data, letting Hibernate persist it for us. 11: */ 12:public class CreateTest { 13: 14: /** 15: * Look up an artist record given a name. 16: * @param name the name of the artist desired. 17: * @param create controls whether a new record should be created if 18: * the specified artist is not yet in the database. 19: * @param session the Hibernate session that can retrieve data 20: * @return the artist with the specified name, or <code>null</code> if no 21: * such artist exists and <code>create</code> is <code>false</code>. 22: * @throws HibernateException if there is a problem. 23: */ 24: public static Artist getArtist(String name, boolean create, 25: Session session) 26: throws HibernateException 27: { 28: Query query = session.getNamedQuery( 29: "com.oreilly.hh.artistByName"); 30: query.setString("name", name); 31: Artist found = (Artist)query.uniqueResult(); 32: if (found == null && create) { 33: found = new Artist(name, null, new HashSet()); 34: session.save(found); 35: } 36: if (found != null && found.getActualArtist() != null) { 37: return found.getActualArtist(); 38: } 39: return found; 40: } 41: 42: /** 43: * Utility method to associate an artist with a track 44: */ 45: private static void addTrackArtist(Track track, Artist artist) { 46: track.getArtists().add(artist); 47: } 48: 49: public static void main(String args[]) throws Exception { 50: // Create a configuration based on the properties file we've put 51: // in the standard place. 52: Configuration config = new Configuration(); 53: 54: // Tell it about the classes we want mapped, taking advantage of 55: // the way we've named their mapping documents. 56: config.addClass(Track.class).addClass(Artist.class); 57: 58: // Get the session factory we can use for persistence 59: SessionFactory sessionFactory = config.buildSessionFactory(); 60: 61: // Ask for a session using the JDBC information we've configured 62: Session session = sessionFactory.openSession(); 63: Transaction tx = null; 64: try { 65: // Create some data and persist it 66: tx = session.beginTransaction(); 67: 68: Track track = new Track("Russian Trance", 69: "vol2/album610/track02.mp3", 70: Time.valueOf("00:03:30"), new Date(), 71: (short)0, new HashSet(), new HashSet()); 72: addTrackArtist(track, getArtist("PPK", true, session)); 73: session.save(track); 74: 75: track = new Track("Video Killed the Radio Star", 76: "vol2/album611/track12.mp3", 77: Time.valueOf("00:03:49"), new Date(), 78: (short)0, new HashSet(), new HashSet()); 79: addTrackArtist(track, getArtist("The Buggles", true, session)); 80: session.save(track); 81: 82: 83: track = new Track("Gravity's Angel", 84: "vol2/album175/track03.mp3", 85: Time.valueOf("00:06:06"), new Date(), 86: (short)0, new HashSet(), new HashSet()); 87: addTrackArtist(track, getArtist("Laurie Anderson", true, session)); 88: session.save(track); 89: 90: track = new Track("Adagio for Strings (Ferry Corsten Remix)", 91: "vol2/album972/track01.mp3", 92: Time.valueOf("00:06:35"), new Date(), 93: (short)0, new HashSet(), new HashSet()); 94: addTrackArtist(track, getArtist("William Orbit", true, session)); 95: addTrackArtist(track, getArtist("Ferry Corsten", true, session)); 96: addTrackArtist(track, getArtist("Samuel Barber", true, session)); 97: session.save(track); 98: 99: track = new Track("Adagio for Strings (ATB Remix)", 100: "vol2/album972/track02.mp3", 101: Time.valueOf("00:07:39"), new Date(), 102: (short)0, new HashSet(), new HashSet()); 103: addTrackArtist(track, getArtist("William Orbit", true, session)); 104: addTrackArtist(track, getArtist("ATB", true, session)); 105: addTrackArtist(track, getArtist("Samuel Barber", true, session)); 106: session.save(track); 107: 108: track = new Track("The World '99", 109: "vol2/singles/pvw99.mp3", 110: Time.valueOf("00:07:05"), new Date(), 111: (short)0, new HashSet(), new HashSet()); 112: addTrackArtist(track, getArtist("Pulp Victim", true, session)); 113: addTrackArtist(track, getArtist("Ferry Corsten", true, session)); 114: session.save(track); 115: 116: track = new Track("Test Tone 1", 117: "vol2/singles/test01.mp3", 118: Time.valueOf("00:00:10"), new Date(), 119: (short)0, new HashSet(), new HashSet()); 120: track.getComments().add("Pink noise to test equalization"); 121: session.save(track); 122: 123: // We're done; make our changes permanent 124: tx.commit(); 125: 126: } catch (Exception e) { 127: if (tx != null) { 128: // Something went wrong; discard all partial changes 129: tx.rollback(); 130: } 131: throw e; 132: } finally { 133: // No matter what, close the session 134: session.close(); 135: } 136: 137: // Clean up after ourselves 138: sessionFactory.close(); 139: } 140:} |
Ahora un ejemplo que emplea los datos almacenados para crear "Albums"
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.*; 8: 9:/** 10: * Create sample album data, letting Hibernate persist it for us. 11: */ 12:public class AlbumTest { 13: 14: /** 15: * Quick and dirty helper method to handle repetitive portion of creating 16: * album tracks. A real implementation would have much more flexibility. 17: */ 18: private static void addAlbumTrack(Album album, String title, String file, 19: Time length, Artist artist, int disc, 20: int positionOnDisc, Session session) 21: throws HibernateException 22: { 23: Track track = new Track(title, file, length, new Date(), (short)0, 24: new HashSet(), new HashSet()); 25: track.getArtists().add(artist); 26: session.save(track); 27: album.getTracks().add(new AlbumTrack(disc, positionOnDisc, track)); 28: } 29: 30: public static void main(String args[]) throws Exception { 31: // Create a configuration based on the properties file we've put 32: // in the standard place. 33: Configuration config = new Configuration(); 34: 35: // Tell it about the classes we want mapped. 36: config.addClass(Track.class).addClass(Artist.class); 37: config.addClass(Album.class); 38: 39: // Get the session factory we can use for persistence 40: SessionFactory sessionFactory = config.buildSessionFactory(); 41: 42: // Ask for a session using the JDBC information we've configured 43: Session session = sessionFactory.openSession(); 44: Transaction tx = null; 45: try { 46: // Create some data and persist it 47: tx = session.beginTransaction(); 48: 49: Artist artist = CreateTest.getArtist("Martin L. Gore", true, 50: session); 51: List albumTracks = new ArrayList(5); 52: Album album = new Album("Counterfeit e.p.", 1, new Date(), 53: albumTracks, new HashSet(), new HashSet()); 54: album.getArtists().add(artist); 55: session.save(album); 56: 57: addAlbumTrack(album, "Compulsion", "vol1/album83/track01.mp3", 58: Time.valueOf("00:05:29"), artist, 1, 1, session); 59: addAlbumTrack(album, "In a Manner of Speaking", 60: "vol1/album83/track02.mp3", Time.valueOf("00:04:21"), 61: artist, 1, 2, session); 62: addAlbumTrack(album, "Smile in the Crowd", 63: "vol1/album83/track03.mp3", Time.valueOf("00:05:06"), 64: artist, 1, 3, session); 65: addAlbumTrack(album, "Gone", "vol1/album83/track04.mp3", 66: Time.valueOf("00:03:32"), artist, 1, 4, session); 67: addAlbumTrack(album, "Never Turn Your Back on Mother Earth", 68: "vol1/album83/track05.mp3", Time.valueOf("00:03:07"), 69: artist, 1, 5, session); 70: addAlbumTrack(album, "Motherless Child", "vol1/album83/track06.mp3", 71: Time.valueOf("00:03:32"), artist, 1, 6, session); 72: 73: System.out.println(album); 74: 75: // We're done; make our changes permanent 76: tx.commit(); 77: 78: // Expermients discussed in "Lifecycle Associations" 79: //tx = session.beginTransaction(); 80: //album.getTracks().remove(1); 81: //session.update(album); 82: //tx.commit(); 83: // 84: //tx = session.beginTransaction(); 85: //session.delete(album); 86: //tx.commit(); 87: 88: } catch (Exception e) { 89: if (tx != null) { 90: // Something went wrong; discard all partial changes 91: tx.rollback(); 92: } 93: throw e; 94: } finally { 95: // No matter what, close the session 96: session.close(); 97: } 98: 99: // Clean up after ourselves 100: sessionFactory.close(); 101: } 102:} |
digital@localhost:~/SourceExamples/SourceExamples/ch05>
ant ctest Buildfile: build.xml prepare: compile: ctest: BUILD SUCCESSFUL prepare: compile: atest: BUILD SUCCESSFUL |
mysql> select * from ALBUM; +----------+------------------+----------+------------+ | ALBUM_ID | TITLE | numDiscs | added | +----------+------------------+----------+------------+ | 1 | Counterfeit e.p. | 1 | 2005-02-17 | +----------+------------------+----------+------------+ 1 row in set (0.01 sec) mysql> select * from ALBUM_ARTISTS; +----------+-----------+ | ALBUM_ID | ARTIST_ID | +----------+-----------+ | 1 | 9 | +----------+-----------+ 1 row in set (0.00 sec) mysql> select * from ALBUM_COMMENTS; Empty set (0.00 sec) mysql> select * from ALBUM_TRACKS; +----------+----------+------+----------------+-----+ | ALBUM_ID | TRACK_ID | disc | positionOnDisc | POS | +----------+----------+------+----------------+-----+ | 1 | 8 | 1 | 1 | 0 | | 1 | 9 | 1 | 2 | 1 | | 1 | 10 | 1 | 3 | 2 | | 1 | 11 | 1 | 4 | 3 | | 1 | 12 | 1 | 5 | 4 | | 1 | 13 | 1 | 6 | 5 | +----------+----------+------+----------------+-----+ 6 rows in set (0.00 sec) mysql> select * from ARTIST; +-----------+-----------------+--------------+ | ARTIST_ID | NAME | actualArtist | +-----------+-----------------+--------------+ | 1 | PPK | NULL | | 2 | The Buggles | NULL | | 3 | Laurie Anderson | NULL | | 4 | William Orbit | NULL | | 5 | Ferry Corsten | NULL | | 6 | Samuel Barber | NULL | | 7 | ATB | NULL | | 8 | Pulp Victim | NULL | | 9 | Martin L. Gore | NULL | +-----------+-----------------+--------------+ 9 rows in set (0.01 sec) mysql> select * from TRACK; +----------+------------------------------------------+---------------------------+----------+------------+--------+ | TRACK_ID | TITLE | filePath | playTime | added | volume | +----------+------------------------------------------+---------------------------+----------+------------+--------+ | 1 | Russian Trance | vol2/album610/track02.mp3 | 00:03:30 | 2005-02-17 | 0 | | 2 | Video Killed the Radio Star | vol2/album611/track12.mp3 | 00:03:49 | 2005-02-17 | 0 | | 3 | Gravity's Angel | vol2/album175/track03.mp3 | 00:06:06 | 2005-02-17 | 0 | | 4 | Adagio for Strings (Ferry Corsten Remix) | vol2/album972/track01.mp3 | 00:06:35 | 2005-02-17 | 0 | | 5 | Adagio for Strings (ATB Remix) | vol2/album972/track02.mp3 | 00:07:39 | 2005-02-17 | 0 | | 6 | The World '99 | vol2/singles/pvw99.mp3 | 00:07:05 | 2005-02-17 | 0 | | 7 | Test Tone 1 | vol2/singles/test01.mp3 | 00:00:10 | 2005-02-17 | 0 | | 8 | Compulsion | vol1/album83/track01.mp3 | 00:05:29 | 2005-02-17 | 0 | | 9 | In a Manner of Speaking | vol1/album83/track02.mp3 | 00:04:21 | 2005-02-17 | 0 | | 10 | Smile in the Crowd | vol1/album83/track03.mp3 | 00:05:06 | 2005-02-17 | 0 | | 11 | Gone | vol1/album83/track04.mp3 | 00:03:32 | 2005-02-17 | 0 | | 12 | Never Turn Your Back on Mother Earth | vol1/album83/track05.mp3 | 00:03:07 | 2005-02-17 | 0 | | 13 | Motherless Child | vol1/album83/track06.mp3 | 00:03:32 | 2005-02-17 | 0 | +----------+------------------------------------------+---------------------------+----------+------------+--------+ 13 rows in set (0.00 sec) mysql> select * from TRACK_ARTISTS; +-----------+----------+ | ARTIST_ID | TRACK_ID | +-----------+----------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 4 | | 6 | 4 | | 4 | 5 | | 6 | 5 | | 7 | 5 | | 5 | 6 | | 8 | 6 | | 9 | 8 | | 9 | 9 | | 9 | 10 | | 9 | 11 | | 9 | 12 | | 9 | 13 | +-----------+----------+ 17 rows in set (0.00 sec) mysql> select * from TRACK_COMMENTS; +----------+---------------------------------+ | TRACK_ID | COMMENT | +----------+---------------------------------+ | 7 | Pink noise to test equalization | +----------+---------------------------------+ 1 row in set (0.00 sec) mysql> |
Ahora realizamos algunas búsquedas de los elementos almacenados:
1:package com.oreilly.hh; 2: 3:import net.sf.hibernate.*; 4:import net.sf.hibernate.cfg.Configuration; 5: 6:import java.sql.Time; 7:import java.util.*; 8: 9:/** 10: * Retrieve data as objects 11: */ 12:public class QueryTest { 13: 14: /** 15: * Retrieve any tracks that fit in the specified amount of time. 16: * 17: * @param length the maximum playing time for tracks to be returned. 18: * @param session the Hibernate session that can retrieve data. 19: * @return a list of {@link Track}s meeting the length restriction. 20: * @throws HibernateException if there is a problem. 21: */ 22: public static List tracksNoLongerThan(Time length, Session session) 23: throws HibernateException 24: { 25: Query query = session.getNamedQuery( 26: "com.oreilly.hh.tracksNoLongerThan"); 27: query.setTime("length", length); 28: return query.list(); 29: } 30: 31: /** 32: * Build a parenthetical, comma-separated list of artist names. 33: * @param artists the artists whose names are to be displayed. 34: * @return formatted list, or an empty string if the set was empty. 35: */ 36: public static String listArtistNames(Set artists) { 37: StringBuffer result = new StringBuffer(); 38: for (Iterator iter = artists.iterator(); iter.hasNext(); ) { 39: Artist artist = (Artist)iter.next(); 40: result.append((result.length() == 0) ? "(" : ", "); 41: result.append(artist.getName()); 42: } 43: if (result.length() > 0) { 44: result.append(") "); 45: } 46: return result.toString(); 47: } 48: 49: /** 50: * Look up and print some tracks when invoked from the command line. 51: */ 52: public static void main(String args[]) throws Exception { 53: // Create a configuration based on the properties file we've put 54: // in the standard place. 55: Configuration config = new Configuration(); 56: 57: // Tell it about the classes we want mapped, taking advantage of 58: // the way we've named their mapping documents. 59: config.addClass(Track.class).addClass(Artist.class); 60: 61: // Get the session factory we can use for persistence 62: SessionFactory sessionFactory = config.buildSessionFactory(); 63: 64: // Ask for a session using the JDBC information we've configured 65: Session session = sessionFactory.openSession(); 66: try { 67: // Print the tracks that will fit in seven minutes 68: List tracks = tracksNoLongerThan(Time.valueOf("00:07:00"), 69: session); 70: for (ListIterator iter = tracks.listIterator() ; 71: iter.hasNext() ; ) { 72: Track aTrack = (Track)iter.next(); 73: System.out.println("Track: \"" + aTrack.getTitle() + "\" " + 74: listArtistNames(aTrack.getArtists()) + 75: aTrack.getPlayTime()); 76: for (Iterator comIter = aTrack.getComments().iterator() ; 77: comIter.hasNext() ; ) { 78: System.out.println(" Comment: " + comIter.next()); 79: } 80: } 81: } finally { 82: // No matter what, close the session 83: session.close(); 84: } 85: 86: // Clean up after ourselves 87: sessionFactory.close(); 88: } 89:} |
Ejecutamos la búsqueda:
digital@localhost:~/SourceExamples/SourceExamples/ch05>
ant qtest Buildfile: build.xml prepare: compile: qtest: BUILD SUCCESSFUL |
Otras características de Hibernate
Lazy Relations
29: <set name="artists" table="TRACK_ARTISTS" lazy="true"> 30: <key column="TRACK_ID"/> 31: <many-to-many class="com.oreilly.hh.Artist" column="ARTIST_ID"/> 32: </set> |
Eliminación y Agregación en Cascada
Album.hbm.xml |
34: <list name="tracks" table="ALBUM_TRACKS" cascade="all"> 35: <meta attribute="use-in-tostring">true</meta> 36: <key column="ALBUM_ID"/> 37: <index column="POS"/> 38: <composite-element class="com.oreilly.hh.AlbumTrack"> 39: <many-to-one name="track" class="com.oreilly.hh.Track" cascade="all"> 40: <meta attribute="use-in-tostring">true</meta> 41: <column name="TRACK_ID"/> 42: </many-to-one> 43: <property name="disc" type="integer" not-null="true"/> 44: <property name="positionOnDisc" type="integer" not-null="true"/> 45: </composite-element> 46: </list> |
AlbumTest.java |
14: /** 15: * Quick and dirty helper method to handle repetitive portion of creating 16: * album tracks. A real implementation would have much more flexibility. 17: */ 18: private static void addAlbumTrack(Album album, String title, String file, 19: Time length, Artist artist, int disc, 20: int positionOnDisc, Session session) 21: throws HibernateException 22: { 23: Track track = new Track(title, file, length, new Date(), (short)0, 24: new HashSet(), new HashSet()); 25: track.getArtists().add(artist); 26: // session.save(track); 27: album.getTracks().add(new AlbumTrack(disc, positionOnDisc, track)); 28: } 29: |
Tipos de consultas
Ejemplo de HQL y SQL
53: 54: <query name="com.oreilly.hh.tracksNoLongerThan"> 55: <![CDATA[ 56: select track.id, track.title from com.oreilly.hh.Track as track 57: where track.playTime <= :length 58: order by track.title desc 59: ]]> 60: </query> 61: 69: 70: <sql-query name="com.oreilly.hh.tracksEndingAt"> 71: <return alias="track" class="com.oreilly.hh.Track"/> 72: <![CDATA[ 73: select {track.*} 74: from TRACK as {track} 75: where SECOND({track}.PLAYTIME) = :seconds 76: ]]> 77: </sql-query> 78: 79:</hibernate-mapping> |
30: 31: public static List tracksEndingAt(int seconds, Session session) 32: throws HibernateException 33: { 34: Query query = session.getNamedQuery( 35: "com.oreilly.hh.tracksEndingAt"); 36: query.setInteger("seconds", seconds); 37: return query.list(); 38: } 39: |