ORM Mapping inheritance with two strategies at once in JPA? - java

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.

Related

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

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
}

JPA OneToMany Association from superClass

I’m trying to map the inheritance from the superclass LendingLine and the subclasses Line and BlockLine. LendingLine has an ManyToOne association with Lending.
When I try to get the LendingLines from the database without the inheritance it works fine. The association works also. But when i add the inheritance, lendingLines in Lending is empty. I also can't get any LendingLines from the DB with the inheritance.
Can anybody help me?
(Sorry for the bad explanation)
Thanks in advance!
LendingLine:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
#DiscriminatorValue(value="Line")
#Table(name = "LendingLine")
public class LendingLine {
...
public LendingLine(){}
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER, targetEntity=Lending.class)
#JoinColumn(name = "LendingId")
private Lending lending;
...
Lending:
#Entity
#Table(name = "Lending")
public class Lending {
...
public Lending(){}
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER, mappedBy = "lending")
private List<LendingLine> lendingLines;
...
BlockDate:
#Entity
#DiscriminatorValue(value = "BlockLine")
public class BlockLine extends LendingLine {
public BlockLine(){
}
}
LendingLineRepository:
This class only reads from the db because the db was created by another application ( C#) where the objects are added to the db.
public class LendingLineRepository extends JpaUtil implement LendingLineRepositoryInterface {
#Override
protected Class getEntity() {
return LendingLine.class;
}
#Override
public Collection<LendingLine> findAll() {
Query query = getEm().createQuery("SELECT l FROM LendingLine l");
System.out.println(query.getResultList().size());
return (Collection<LendingLine>) query.getResultList();
}
Table LendingLine:
Choose your type of superclass according to your needs:
Concrete Class
public class SomeClass {}
Define your superclass as a concrete class, when you want to query it and when you use a new operator for further logic. You will always be able to persist it directly. In the discriminator column this entity has it's own name. When querying it, it returns just instances of itself and no subclasses.
Abstract Class
public abstract class SomeClass {}
Define your superclass as an abstract class when you want to query it, but don't actually use a new operator, because all logic handled is done by it's subclasses. Those classes are usually persisted by its subclasses but can still be persisted directly. U can predefine abstract methods which any subclass will have to implement (almost like an interface). In the discriminator column this entity won't have a name. When querying it, it returns itself with all subclasses, but without the additional defined information of those.
MappedSuperclass
#MappedSuperclass
public abstract class SomeClass {}
A superclass with the interface #MappedSuperclass cannot be queried. It provides predefined logic to all it's subclasses. This acts just like an interface. You won't be able to persist a mapped superclass.
For further information: JavaEE 7 - Entity Inheritance Tutorial
Original message
Your SuperClass LendingLine needs to define a #DiscriminatorValue as well, since it can be instantiated and u use an existing db-sheme, where this should be defined.

What is the best way to persist a hierarchy with an abstract class w/o a table

I have a simple inheritance model:
public abstract class Base {
int id;
string name;
}
public class Derived1 extends Base {
int valueD1;
}
public class Derived2 extends Base {
int valueD2;
}
How should I map the classes (with JPA annotations) so that I have separate tables for Derived1 and Derived2 (Table per concrete class), and no table for Base.
Should I use #MappedSuperclass, or #Embeddable (and skip inheritance), or #Inheritance?
Use #MappedSuperclass, and define distinct tables for each entity, IMHO,
But it depends on if you will most likely query for the parent class or if you use both derived entities for themselves, without having the need to query two tables.

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;
}

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