venerdì 3 aprile 2009

Relazione many-to-many con attributi con Hibernate

Mappare una molti-a-molti semplice con Hibernate usando le annotations è un'operazione piuttosto immediata, le cose si complicano quando si vanno ad aggiungere proprietà aggiuntive a questa relazione. Seguendo il manuale "Java Persistence With Hibernate", ecco l'esempio della mappatura di una relazione molti-a-molti con attributi, realizzata esplicitando la join table messa in relazione uno-a-molti con entrambe le tabelle interessate. Le tabelle in questione sono "Utente" e "Movie", in relazione molti-a-molti e mappate dalla join table utente_movie.

Ecco il codice delle classi con cui è stata realizzata la mappatura:


UTENTE

package it.flavio.moltiamolti.model;

import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.springmodules.validation.bean.conf.loader.annotation.handler.Length;


/**
* Object mapping for hibernate-handled table: movie.
* @author autogenerated
*/

@Entity
@Table(name = "utente", catalog = "moltiamolti")
public class Utente implements Cloneable, Serializable {

/** Serial Version UID. */
private static final long serialVersionUID = -559009206L;

/** Use a WeakHashMap so entries will be garbage collected once all entities
referring to a saved hash are garbage collected themselves. */
private static final Map SAVED_HASHES =
Collections.synchronizedMap(new WeakHashMap());

/** hashCode temporary storage. */
private volatile Integer hashCode;
private Set utenteToMovies;

/** Field mapping. */
private String name;
/** Field mapping. */
private Long id = 0L; // init for hibernate bug workaround

/**
* Default constructor, mainly for hibernate use.
*/
public Utente() {
// Default constructor
}

/** Constructor taking a given ID.
* @param id to set
*/
public Utente(Long id) {
this.id = id;
}


/** Return the type of this class. Useful for when dealing with proxies.
* @return Defining class.
*/
@Transient
public Class getClassType() {
return Utente.class;
}


/**
* Return the value associated with the column: duration.
* @return A String object (this.duration)
*/
@Length(max=45)
@Column( length = 45 )
public String getName() {
return this.name;

}


/**
* Set the value related to the column: duration.
* @param duration the duration value you wish to set
*/
public void setName(final String name) {
this.name = name;
}

/**
* Return the value associated with the column: id.
* @return A Integer object (this.id)
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column( name = "utente" )
public Long getId() {
return this.id;

}



/**
* Set the value related to the column: id.
* @param id the id value you wish to set
*/
public void setId(final Long id) {
// If we've just been persisted and hashCode has been
// returned then make sure other entities with this
// ID return the already returned hash code
if ( (this.id == null || this.id == 0) &&
(id != null) &&
(this.hashCode != null) ) {
SAVED_HASHES.put( id, this.hashCode );
}
this.id = id;
}


@Column( nullable = false )
@OneToMany( mappedBy = "utente" )
public Set getUtenteToMovies() {
return utenteToMovies;
}

public void setUtenteToMovies(Set utenteToMovies) {
this.utenteToMovies = utenteToMovies;
}



/**
* Deep copy.
* @return cloned object
* @throws CloneNotSupportedException on error
*/
@Override
public Utente clone() throws CloneNotSupportedException {
super.clone(); // keep hierarchy
final Utente copy = new Utente();


copy.setName(this.getName());
copy.setId(this.getId());

return copy;
}


/** Provides toString implementation.
* @see java.lang.Object#toString()
* @return String representation of this class.
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer();

sb.append("duration: " + this.getName() + ", ");
sb.append("id: " + this.getId() + ", ");

return sb.toString();
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;


result = prime * result
+ ((name == null) ? 0 : name.hashCode());

result = prime * result
+ ((hashCode == null) ? 0 : hashCode.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());

return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Utente other = (Utente) obj;

if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;


if (hashCode == null) {
if (other.hashCode != null)
return false;
} else if (!hashCode.equals(other.hashCode))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;

return true;
}

}





MOVIE

package it.flavio.moltiamolti.model;

import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.springmodules.validation.bean.conf.loader.annotation.handler.Length;


/**
* Object mapping for hibernate-handled table: movie.
* @author autogenerated
*/

@Entity
@Table(name = "movie", catalog = "moltiamolti")
public class Movie implements Cloneable, Serializable {

/** Serial Version UID. */
private static final long serialVersionUID = -559009206L;

/** Use a WeakHashMap so entries will be garbage collected once all entities
referring to a saved hash are garbage collected themselves. */
private static final Map SAVED_HASHES =
Collections.synchronizedMap(new WeakHashMap());

/** hashCode temporary storage. */
private volatile Integer hashCode;
private Set utenteToMovies;



/** Field mapping. */
private String duration;
/** Field mapping. */
private Long id = 0L; // init for hibernate bug workaround

/**
* Default constructor, mainly for hibernate use.
*/
public Movie() {
// Default constructor
}

/** Constructor taking a given ID.
* @param id to set
*/
public Movie(Long id) {
this.id = id;
}


/** Return the type of this class. Useful for when dealing with proxies.
* @return Defining class.
*/
@Transient
public Class getClassType() {
return Movie.class;
}







/**
* Return the value associated with the column: duration.
* @return A String object (this.duration)
*/
@Length(max=45)
@Column( length = 45 )
public String getDuration() {
return this.duration;

}



/**
* Set the value related to the column: duration.
* @param duration the duration value you wish to set
*/
public void setDuration(final String duration) {
this.duration = duration;
}

/**
* Return the value associated with the column: id.
* @return A Integer object (this.id)
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column( name = "movie" )
public Long getId() {
return this.id;

}



/**
* Set the value related to the column: id.
* @param id the id value you wish to set
*/
public void setId(final Long id) {
// If we've just been persisted and hashCode has been
// returned then make sure other entities with this
// ID return the already returned hash code
if ( (this.id == null || this.id == 0) &&
(id != null) &&
(this.hashCode != null) ) {
SAVED_HASHES.put( id, this.hashCode );
}
this.id = id;
}



/**
* Return the value associated with the column: itemOrder.
* @return A Set<ItemOrder> object (this.itemOrder)
*/
@Column( nullable = false )
@OneToMany( mappedBy = "movie" )
public Set getUtenteToMovies() {
return utenteToMovies;
}

public void setUtenteToMovies(Set utenteToMovies) {
this.utenteToMovies = utenteToMovies;
}







/**
* Deep copy.
* @return cloned object
* @throws CloneNotSupportedException on error
*/
@Override
public Movie clone() throws CloneNotSupportedException {
super.clone(); // keep hierarchy
final Movie copy = new Movie();


copy.setDuration(this.getDuration());
copy.setId(this.getId());

return copy;
}


/** Provides toString implementation.
* @see java.lang.Object#toString()
* @return String representation of this class.
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer();

sb.append("duration: " + this.getDuration() + ", ");
sb.append("id: " + this.getId() + ", ");

return sb.toString();
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;


result = prime * result
+ ((duration == null) ? 0 : duration.hashCode());

result = prime * result
+ ((hashCode == null) ? 0 : hashCode.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());

return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Movie other = (Movie) obj;

if (duration == null) {
if (other.duration != null)
return false;
} else if (!duration.equals(other.duration))
return false;


if (hashCode == null) {
if (other.hashCode != null)
return false;
} else if (!hashCode.equals(other.hashCode))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;

return true;
}


}




UTENTETOMOVIE


package it.flavio.moltiamolti.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


/**
* Object mapping for hibernate-handled table: movie.
* @author autogenerated
*/

@Entity
@Table(name = "utente_movie", catalog = "moltiamolti")
public class UtenteToMovie implements Cloneable, Serializable {

@Embeddable
public static class Id implements Serializable {
@Column(name = "movie_id")
private Long movieId;

@Column(name = "utente_id")
private Long utenteId;

public Id() {}
public Id(Long movieId, Long utenteId) {
this.movieId = movieId;
this.utenteId = utenteId;
}
public boolean equals(Object o) {
if (o != null && o instanceof Id) {
Id that = (Id)o;
return this.movieId.equals(that.movieId) &&
this.utenteId.equals(that.utenteId);
} else {
return false;
}
}
public int hashCode() {
return movieId.hashCode() + utenteId.hashCode();
}
}


@EmbeddedId
private Id id = new Id();

@ManyToOne
@JoinColumn(name="utente_id",
insertable = false,
updatable = false)
private Utente utente;

@ManyToOne
@JoinColumn(name="movie_id",
insertable = false,
updatable = false)
private Movie movie;



private String quantity;
@Column(name = "quantity" , length = 50)
public String getQuantiy(){
return this.quantity;
}

public void setQuantity(String quantity){
this.quantity = quantity;
}



public UtenteToMovie() {}
public UtenteToMovie( Movie movie,
Utente utente) {
// Set fields
//this.username = username;
this.movie = movie;
this.utente = utente;
// Set identifier values
this.id.movieId = movie.getId();
this.id.utenteId = utente.getId();
// Guarantee referential integrity
movie.getUtenteToMovies().add(this);
utente.getUtenteToMovies().add(this);
}




public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
public Utente getUtente() {
return utente;
}
public void setUtente(Utente utente) {
this.utente = utente;
}
public Movie getMovie() {
return movie;
}
public void setMovie(Movie movie) {
this.movie = movie;
}


}

Nessun commento: