Hibernate - OneToMany - Several Columns
I have those 2 tables Teacher and Contact, a teacher can have x Contacts. So here we are looking at a @OneToMany association.
Tables Structure:
User [userid, username, email,...]
Contact [contactid, contactname, ref, reftype,...]
I want to load from my User Class all the user's contacts. To do that I would do a query like
Select * from contact as c WHERE c.ref=8240 AND c.reftype='T';
8240 being a random userid and reftype T being for Teacher. As this contact table is used as well for school contacts and/or anyother type of customer we could have. The problem is I have no idea how to do this with Hibernate. Should I use embedbedId? Or a JoinColumns?
What I have done so far is to link my teacher to contacts having contact.ref=teacher.teacherid
but what I want is :
contact.ref=teacher.teacherid AND contact.reftype='T'
开发者_如何学编程
How do I do that?
Here is my code Teacher.class
private Integer teacherid;
private Set<Contact> contact;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "teacherid", unique = true, nullable = false)
public Integer getTeacherId() {
return teacherid;
}
@OneToMany(fetch = FetchType.EAGER)
@JoinColumns({
@JoinColumn(name="ref"),
})
public Set<Contact> getContact() {
return contact;
}
public void setContact(Set<Contact> contact) {
this.contact = contact;
}
Contact.class
@Entity
@Table(name = "contact")
public class Contact implements java.io.Serializable {
private Integer contactid;
private String contactname;
private String contacttype;
private String reftype;
private int ref;
/*private Teacher teacher;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumns({
@JoinColumn(name = "ref"),
@JoinColumn(name = "reftype")
})
public Teacher getTeacher() {
return teacher;
}
public void setTeacher (Teacher teacher) {
this.teacher= teacher;
}
*/
private Set<ContactItem> contactItems;
private Set<ContactAddress> contactAddressess;
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name="contactid")
public Set<ContactItem> getContactItems(){
return contactItems;
}
public void setContactItems(Set<ContactItem> contactItems) {
this.contactItems = contactItems;
}
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name="contactid")
public Set<ContactAddress> getContactAddressess(){
return contactAddressess;
}
public void setContactAddressess(Set<ContactAddress> contactAddressess) {
this.contactAddressess = contactAddressess;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "contactid", unique = true, nullable = false)
public Integer getContactid() {
return this.contactid;
}
public void setContactid(Integer contactid) {
this.contactid = contactid;
}
@Column(name = "contactname", nullable = false)
public String getContactname() {
return this.contactname;
}
public void setContactname(String contactname) {
this.contactname = contactname;
}
@Column(name = "contacttype", nullable = false)
public String getContacttype() {
return this.contacttype;
}
public void setContacttype(String contacttype) {
this.contacttype = contacttype;
}
@Column(name = "reftype", nullable = false, length = 1)
public String getReftype() {
return this.reftype;
}
public void setReftype(String reftype) {
this.reftype = reftype;
}
@Column(name = "ref", nullable = false)
public int getRef() {
return this.ref;
}
public void setRef(int ref) {
this.ref = ref;
}
public String toString(){
return "\n#"+this.contactname+" : ("+this.ref+"-"+this.reftype+") \n"
+"#Items-----\n"+getContactItems()+"\n"
+"#Address---\n"+getContactAddressess()+"\n";
}
}
Assuming that Teacher
is a User
, and that every user has contacts
.
User.class
@OneToMany(mappedBy = "user", targetEntity = Contact.class, orphanRemoval=true)
@Cascade(CascadeType.ALL)
private Set<Contact> contacts = new ConcurrentSkipListSet<Contact>();
//No setContacts here.
Contact.class
@ManyToOne
private User user;
public void setUser(User user){
this.user = user;
}
That's it.
First, since there's a User table and no Teacher table (teachers seem to be a sub-set of user rows, denoted by a 'type' column) I wouldn't have a table of User and a Teacher model. I would have only a User model instead. Hibernate is much easier if you do things the Hibernate way, which is one model per table with the model having the same name. For example, if you do this, you can use a tool to auto-generate (reverse engineer) all your model classes. This means a Hibernate tool will look at your tables, foreign keys, etc and generate appropiate Java code for your tables. Very very convenient when you start making table changes.
Normally you'll reverse engineer the model classes. Since these are machine-generated you don't want to change them because the changes will be over-written the next time to reverse-engineer the models. What I do for conditions such as yours is to create a class called a DAO - Data Access Object, or DAO.
public class UserDAO {
public static User getTeacher(EntityManager em, Long id) {
try {
IForgotTheType query = em.createQuery("User from User user, Contact contact where contact.ref=user.teacherid AND contact.reftype='T' and User.id=:id");
query.setParameter("id", id);
return (User) query.getSingleResult();
} catch (NoResultException e) {
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Obviously I am not sure about your table structure and column names but you get the idea. You can see where I inserted your code into the query above. Now you can get a teacher by simply calling UserDAO.getTeacher(). Use DAOs - otherwise you'll have Hibernate code everywhere in your code making maintenance more difficult.
Check out section 3.4 of this.
精彩评论