How to inherit and replace a #Entity from commons package? - java

I have an #Entity in a commons package:
#Entity("person")
public class Person {
//fields...
}
In an implementing application, I want to extend this entity with some custom fields.
But I still want to map to table person:
#Entity("person")
public class Person extends org.commons.Person {
//additional fields
}
Result:
Caused by: org.hibernate.DuplicateMappingException: The [Person] and [CustomPerson] entities
share the same JPA entity name: [person] which is not allowed
So how can I extend that entity and tell spring to somehow "forget" about the parent Person entity, so that only my CustomPerson is loaded?

The problem is that you are assigning the same name to both entities. You don't need to do that. You can annotate your parent entity with #Entity, #Table and #Inheritance (which by default employs single table inheritance) and your subclass entities with just #Entity:
#Entity
#Table("person")
#Inheritance
public class Person {
//fields...
}
#Entity
public class CustomPerson extends Person {
//additional fields
}

Related

How to annotate composition of abstract class instance?

I have a design of Person as shown in the following picture. The design is to allow a person to change his role from Staff to Student, Student to Faculty and so on.
I want to persist this system to DB using hibernate annotation. Does anyone know how to do that?
Thanks a lot!
So you have 1:N relation between Entity Persona and abstract entity Person Role. Think this may work for you.
#Entity
public class Person {
// Here you have all roles in some collection.
#OneToMany(mappedBy="person", fetch=FetchType.LAZY)
private List<PersonRole> roles;
...
}
#Entity
public abstract class PersonRole {
#ManyToOne
#JoinColumn(name="PERSON_ID")
private Person person;
...
}
#Entity
public class Staff extends PersonRole {
...
}
Also don't forget to set proper
#Inheritance(strategy=InheritanceType.<strategy>)
to define how class model is mapped to relational model.
Edit: Unfortunately #MappedSuperclass can't be used in relations mapping so this is not an option here as long as you would like to have PersonRole collection in Person entity.

Embedded single table mapping

I'm facing an issue with modelling hibernate mapping. Here is what i have:
#Entity
#Table
public class Entry {
#Id private long id;
#Embedded private Content content;
...
}
#MappedSuperclass
#DiscriminatorColumn(name="content_type")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Content {
#Column(name="content_type") private String type;
...
}
#Embeddable
#DiscriminatorValue("A")
public class AContent extends Content {
...
}
#Embeddable
#DiscriminatorValue("B")
public class BContent extends Content {
...
}
I'd like to have that all subclasses of Content to be mapped as embedded onto the Entry class.
In other words, in result i'd like to have one Entry table with columns from all subclasses of Content.
Currently the persisting Entry test says that:
javax.persistence.PersistenceException: org.hibernate.InstantiationException:
Cannot instantiate abstract class or interface: : foo.bar.Content
So it seems that loading fails because instead of getting AContent it tries to instantiate abstract Content.
Any ideas?
Spec says...
An entity may inherit from another entity class. Entities support inheritance, polymorphic associations and polymorphic queries.
It says nothing about embeddables being inheritable and thus has no support for inheritance for them.

JPA Inheritance mapping multiple implementations

I have a problem with JPA inheritance. See my entities below. I have a Person that can be in either a House or a Car, never at the same time of course. Both Car and House implement the PersonHoldable interface. I know I cannot map an Entity directly to an interface.
This is my model:
#Entity
public class Person{
private PersonHoldable personHoldable; // either a Car or a House
// This does not work of course because it's an interface
// This would be the way to link objects without taking JPA into consideration.
#OneToOne
public PersonHoldable getPersonHoldable() {
return this.personHoldable;
}
public void setPersonHoldable(PersonHoldable personHoldable) {
this.personHoldable = personHoldable;
}
}
#Entity
public class Car implements PersonHoldable{}
#Entity
public class House implements PersonHoldable{}
public interface PersonHoldable{}
How can I map this correctly in JPA taking the following into consideration?
I tried #MappedSuperclass on an abstract implementation of PersonHoldable. Although it will work for this particular setup, the problem with this is that Car and House in reality implement more interfaces. And they are mapped to other entities as well.
The Person could have a property for every possible PersonHoldable, so in this case it could have a getCar() and getHouse() property. That does not seem very flexible to me. If I would add a Bike implementation of the PersonHoldable I would have to change my Person class.
I can map the other way around, so having a OneToOne relation only on the PersonHoldable implementation side. This would mean adding a getPerson() property to the PersonHoldable. But then it's not very easy from a Person perspective to see what PersonHoldable it is linked to.
I'm using default JPA, so no Hibernate specific tags if possible.
If this is not possible with default JPA, what would be best practice in this case?
A slight variation on your second point would be to make Person have an inheritance type and implement a CarPerson and HousePerson (and later a BikePerson) whose whole purpose is to define the specific join relationship to a specific PersonHolder implementation. That keeps the relationship intact and more easily queryable from the Person side.
#Inheritance(strategy = JOINED)
#DiscriminatorColumn(name="holdableType", discriminatorType=CHAR, length=1)
#Entity
public class Person {
// common fields
}
#Entity
#DiscriminatorValue("C")
public class CarPerson extends Person {
#OneToOne
private Car car;
}
#Entity
#DiscriminatorValue("H")
public class HousePerson extends Person {
#OneToOne
private House house;
}

ORM Mapping inheritance with two strategies at once in JPA?

Now, as far as I know, there are two most used inheritance mapping strategies in JPA:
Single table - where all the classes (both subclasses and superclasses) are mapped in a single table that has as columns all the fields from all the classes; and the fields specific only to some subclasses are NULL in other corresponding entries.
.
#Entity
#Table(name="types")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="types", discriminatorType=DiscriminatorType.STRING, length=1)
public abstract class Base { //... }
#Entity
#DiscriminatorValue(value="A")
public class TypeA extends Base { //... }
#Entity
#DiscriminatorValue(value="B")
public class TypeB extends Base { //... }
Joined table strategy - where there is one table for the base class having as columns all the base class' fields and one other column for type; also there are specific tables for each subclass each having only the corresponding subclass' fields which are mapped one-to-one (by PK) with the base table.
.
#Entity
#Table(name="USERS")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="types",discriminatorType=STRING, length=1)
public abstract class Base { //... }
#Entity
#Table(name="SELLERS")
#DiscriminatorValue(value="A")
#PrimaryKeyJoinColumn(name="base_id")
public class TypeA extends User { //... }
#Entity
#Table(name="BIDDERS")
#DiscriminatorValue(value="B")
#PrimaryKeyJoinColumn(name="base_id")
public class TypeB extends User { //... }
In my domain I have these classes:
public abstract class Base {
//data
}
public class TypeA extends Base {
//only one field
}
public class TypeB extends Base {
// many more fields
}
and I would want a 1. inheritance mapping strategy between TypeA and Base and 2. inheritance mapping strategy between TypeB and Base (this is an oversimplification; there are actually many entities) because I wouldn't want another table for one more field. Is this possible in JPA and does it make any sense?
Edit: I do not know what is wrong with the code formatting...
No, this isn't possible in JPA. You need to configure #Inheritance at the base class level, and it can't be overridden at the subclass level.
Your options do however include one more possibility which you didn't mention, which is InheritanceType.TABLE_PER_CLASS. If you use this, you'd have N tables (for N subclasses) rather than one or N+1. And it works well for some cases, see the advantages/disadvantages in the link.

JPA deep inheritence annotation attributes

I have a hierarchical JPA mapping that is several Classes deep. Something like this
#Entity
#Inheritance(strategy= InheritanceType.SINGLE_TABLE)
public abstract class BaseEntityClass implements Serializable {
// lots of stuff common to all my entities.
}
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class EntityTypeOne extends BaseEntityClass {
// stuff common to EntityTypeOne
}
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class EntityTypeTwo extends BaseEntityClass {
// stuff common to EntityTypeTwo
}
I know you use the #Inheritence method with the superclass to define the mapping strategy. But how does this work with deep hierarchies? I want all the leaf classes to be mapped to their own tables. Should I do SINGLE_TABLE with BaseEntityClass?
Your base class should be marked TABLE_PER_CLASS. Here's an example from OpenJPA:
#Entity
#Table(name="MAG")
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Magazine {
...
}
#Entity
#Table(name="TABLOID")
public class Tabloid
extends Magazine {
...
}
According to the JPA JavaDocs, the #Inheritance annotation should be specified on the root of the class hierarchy:
Defines the inheritance strategy to be used for an entity class
hierarchy. It is specified on the entity class that is the root of the
entity class hierarchy.
It is not specified by the specification if this annotation can be placed on a subclass and as such its behavior is undefined.
So to answer the question you have asked in the comments, if you have this hierarchy:
SubSub -> Sub -> Base
You only need to annotate Base with #Inheritance(strategy = TABLE_PER_CLASS).

Categories