views:

102

answers:

1

Question regarding Hibernate Polymorphism and extending a parent class (which I can not modify directly). My parent class is called Contact:

@Entity 
@Table(name="contact")
@Inheritance(strategy=InheritanceType.JOINED) 
public class Contact {
  @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
  public long id;
  public String name;
} 

And the child class is called ContactLocation which associates a Location to a Contact:

@Entity 
@Table(name="contact_location") 
@Inheritance(strategy=InheritanceType.JOINED) 
public class ContactLocation extends Contact {
  @ManyToOne(targetEntity=Location.class, cascade=CascadeType.ALL)
  Location location;
}

The resulting database table structure appears to be correct:

contact: 
 id:long 
 name:varchar

contact_location: 
 contact_id:long 
 location_id:long

Here's my save method which I need to either update an existing ContactLocation, or save a new ContactLocation for an existing Contact:

public void saveContact(Object dialog) { 
  Contact contact = ui.getAttachedObject(dialog, Contact.class); 
  ContactLocation contactLocation = null; 
  if (contact instanceof ContactLocation) { 
     LOG.debug("Casting Contact to ContactLocation"); 
     contactLocation = (ContactLocation)contact; 
     //TODO Update existing ContactLocation
     //UPDATE contact_location SET location_id = 33 WHERE contact_id = 22;
  } 
  else { 
     LOG.debug("Contact NOT instanceof ContactLocation"); 
     //TODO Save new ContactLocation from existing Contact
     //INSERT INTO contact_location (contact_id, location_id) VALUES (22,33);
  }
}

How do I create a row in *contact_location* table which maps Contact to a Location using my ContactLocationDao?

+1  A: 

There is no support for objects changing type after creation that I'm aware of. You'll have to create a new ContactLocation object, update possible references and then delete the original Contact, I'm afraid.

Henning
Darn, I was afraid of that. Seems like a strange thing because all I really want to do is either:UPDATE contact_location SET location_id = 33 WHERE contact_id = 22;[OR]INSERT INTO contact_location (contact_id, location_id) VALUES (22,33);
Dale Zak
There are a lot of other classes that reference Contact, so I don't think deleting the original Contact is an option...
Dale Zak
You can still do that in SQL if you need to, of course. Hibernate really just provides a way to persist Java class structures to a database; many things that come natural in SQL are harder with objects. Sigh.
Henning
Henning, can you think of a better approach to solve this problem? I basically need to map existing Contacts to a Location, and can not modify the Contact class.
Dale Zak
@Dale: The alternative to a native SQL query is to create an entity that does not inherit from `Contact`, like a `ContactLocation` entity with `contact` and `location` as properties. The downside of such an approach is that there would be no `getLocation()` method on `Contact` objects, but you'd have to find the corresponding Location in code (i.e. call a repository).
Henning
Thinking about it, your original approach carries a similar disadvantage: Every time you look for a location for a contact, you have to use type checks to see if it's a `ContactLocation`, which means you don't really make proper use of the polymorphism, but really just use a switch statement every time the location is relevant. That's not much more elegant than calling a repository to check if a location is available, which I think is what I'd go for given the circumstances.
Henning