Let's suppose I have a JPA entity:
#Entity
#Table(name = "PARENT")
public class Parent {
// ...
}
Is there any way, maybe Hibernate-specific, to create subclass of Parent in a separate table?
#Entity
#Table(name = "CHILD")
public class Child extends Parent {
// ...
}
The main idea is to have set of common entity classes in a base package shared among projects, and extend them only if some project-specific properties are required.
Hibernate Inheritance: Annotation Mapping
Annotate the parent class with #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS). The Hibernate docs (for version 4.3, the new 5.0 docs seem to be missing this section so far) cover this in Chapter 10 and section 5.1.6 of the manual.
In One Table per Concrete class scheme, each concrete class is mapped as normal persistent class. Thus we have 3 tables; PARENT, CHILD to persist the class data. In this scheme, the mapping of the subclass repeats the properties of the parent class.
Following are the advantages and disadvantages of One Table per Subclass scheme.
Advantages
This is the easiest method of Inheritance mapping to implement.
Following is the example where we map Parent and Child entity classes using JPA Annotations.
#Entity
#Table(name = "Parent")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Parent {
// Getter and Setter methods,
}
#Inheritance – 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.
#InheritanceType – Defines inheritance strategy options. TABLE_PER_CLASS is a strategy to map table per concrete class.
#Entity
#Table(name="Child")
public class Child extends Parent {
// Getter and Setter methods,
}
Annotate the parent class with #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS). The Hibernate docs (for version 4.3, the new 5.0 docs seem to be missing this section so far) cover this in Chapter 10 and section 5.1.6 of the manual.
Related
I have and issue with searching in entities that are extended from #MappedSuperclass. I created a class PhoneBook and extended 2 entities from it: FirstPhoneBook and SecondPhoneBook. The structure looks the following:
#MappedSuperclass
public abstract class PhoneBook {
...
#Entity
#Table(name = "first_phone_book")
public class FirstPhoneBook extends PhoneBook {
...
#Entity
#Table(name = "second_phone_book")
public class SecondPhoneBook extends PhoneBook {
...
These tables are absolutely similar. I discribe all fields in PhoneBook class, childs have only default constructor in it. External system sends a phone number as a parameter. Depending on whether tables contain such number or not my system responds with a word.
The question is: how can I search separately in each table that is extended from #MappedSuperclass without hardcoding each child class name?
I could only find variants of search by value like that:
currentSession.get(Employee.class, theId);
but there is explicit call to entity class. I want this to be extendable without need to write new DAO for each new entity added. Current method signature looks the following:
public <T extends PhoneBook> T findByNumber(String number);
What you describe is polymorphic queries, i.e. queries that reference the parent class. The Hibernate documentation says this is not well supported when using #MappedSuperclass inheritance:
Because the #MappedSuperclass inheritance model is not mirrored at the database level, it’s not possible to use polymorphic queries referencing the #MappedSuperclass when fetching persistent objects by their base class.
If polymorphic queries are frequently used, it's better to use the table per class inheritance strategy:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class PhoneBook {
...
#Entity
#Table(name = "first_phone_book")
public class FirstPhoneBook extends PhoneBook {
...
#Entity
#Table(name = "second_phone_book")
public class SecondPhoneBook extends PhoneBook {
...
You can then fetch an entity using the superclass:
PhoneBook phoneBook = currentSession.get(PhoneBook.class, theId);
and Hibernate would typically use a UNION to do the query with both tables.
This being said, even with #MapperSuperclass, Hibernate can still query all tables for classes that extend the parent class. You can use the following JPA query (note that it uses the fully qualified class name of the parent class):
Query<PhoneBook> query = currentSession.createQuery("from " + PhoneBook.class.getName() +
" where id = :id", PhoneBook.class);
query.setParameter("id", theId);
The difference is that here it's not querying an entity, but just all classes that extend a parent class. Also in this case, unlike with the table-per-class strategy, Hibernate will not use a UNION, but send a query to each table, in this case two separate SQL queries instead of one.
I'm going to create a model that implement inheritance concept. I was thinking that it is possible by creating two (or more) tables (one for the parent class and the other for the child class), then create two (or more) model based on the table.
I currently created a model that acts as a parent class, and made it abstract
#NoArgsConstructor // lombok
#AllArgsConstructor // lombok
#Data // lombok
#Entity(name="Account")
#Inheritance
public abstract class AccountModel {
#Id
#Column(name="username")
private String username;
// Some other fields and getters and setters here
}
and then created child class that extends above class
#NoArgsConstructor // lombok
#Data // lombok
#EqualsAndHashCode(callSuper=true) // lombok
#Entity(name="Administrator")
public class AdministratorModel extends AccountModel {
#Id
#Column(name="username")
private String username;
// some other fields and getters and setters here
}
(currently, the username is used as the join)
and I created two repositories for both models
#Repository
public interface AccountRepository extends JpaRepository<AccountModel, String>{};
#Repository
public interface AdministratorRepository extends JpaRepository<AdministratorModel, String>{};
Then, I tested it by trying to save new AdministratorModel object to AdministratorRepository by using JpaRepository.save() method.
I was expecting that this setting will fill data from the object to both of the tables on the database, and automatically mapped all properties to each table. but, the data is only saved as one record on the parent table, and adding new column (one column is something that may refer to child table, and other column is properties of the child table, without adding the join column 'username'), while leaving the child table empty.
I think that I'm doing it wrong.
Then, how to make it works as expected ?
Should I not used inheritance and save the model manually using two (or more) repositories, or should I only create one repository with a custom query, or is there any other way ?
This kind of inheritance should add non default strategy to #Inheritance annotation.
Changing #Inheritance to #Inheritance(strategy=InheritanceType.JOINED) fixes the problem.
As the documentation says this strategy is:
A strategy in which fields that are specific to a
subclass are mapped to a separate table than the fields
that are common to the parent class, and a join is
performed to instantiate the subclass.
I have a single table hierarchy shown below:
#MappedSuperclass
#Table(name = "v_contract_account", schema = "SAP")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#XmlRootElement
#XmlSeeAlso({CurrencyAccount.class, ProgramAccount.class})
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractContractAccount implements Serializable {
....
}
#Entity
#Table(name = "v_contract_account", schema = "SAP")
#Immutable
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER)
#DiscriminatorValue("0")
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class CurrencyAccount extends AbstractContractAccount {
...
}
#Entity
#Table(name = "v_contract_account", schema = "SAP")
#Immutable
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER)
#DiscriminatorValue("1")
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ProgramAccount extends AbstractContractAccount {
...
}
Right now it works as it is (except the discriminator stuff), but why is it that if I remove the table annotation from the subclass, Hibernate will throw an exception?
org.jboss.resteasy.spi.UnhandledException: java.lang.ClassCastException: org.jboss.resteasy.specimpl.BuiltResponse cannot be cast to [Lcom.zanox.internal.billingmasterdata.domain.entity.CurrencyAccount;
And the strange thing is, if I don't put the table and inheritance annotation in the abstract super class, everything still works fine. Does this mean MappedSuperClass doesn't care about the table and inheritance annotation? If the annotation #Inheritance(strategy = InheritanceType.SINGLE_TABLE) is not needed anywhere, then where do I specify it?
Btw, in my case here, Hibernate doesn't create the table, the table is there already and I just want to map it.
You probably want to remove the #MappedSuperClass annotation from your parent Entity and make it a normal Entity.
http://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html
If you wanted to query across AbstractContractAccount then it has to be an Entity. You can cannot do this when it is a MappedSuperclass.
You would use #MappedSuperClass when you wanted to defined some common mapings but where there was no actual 'database inheritance'.
http://en.wikibooks.org/wiki/Java_Persistence/Inheritance
Mapped superclass inheritance allows inheritance to be used in the
object model, when it does not exist in the data model. It is similar
to table per class inheritance, but does not allow querying,
persisting, or relationships to the superclass. Its main purpose is to
allow mappings information to be inherited by its subclasses. The
subclasses are responsible for defining the table, id and other
information, and can modify any of the inherited mappings. A common
usage of a mapped superclass is to define a common PersistentObject
for your application to define common behavior and mappings such as
the id and version. A mapped superclass normally should be an abstract
class. A mapped superclass is not an Entity but is instead defined
though the #MappedSuperclass annotation or the
element.
My class structure looks like this... I have two separate strategies being implemented here but the inheritance strategy of the root class i.e. InheritanceType.JOINED is being used throughout the hierarchy...
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "typeName", discriminatorType = DiscriminatorType.STRING, length = 100)
#Table(name="table_A")
public abstract class A{
...
}
#Entity
#Table(name = "table_B")
#PrimaryKeyJoinColumn(name = "ID_B")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue("SVC")
public abstract class B extends A {
...
}
#Entity
#DiscriminatorValue("C")
public class C extends B {
...
}
#Entity
#DiscriminatorValue("D")
public class D extends B {
...
}
When, I am creating an instance of 'D' and trying to persist it, hibernate is looking for a table named 'D' ...
I found a couple of people asking the same questions... but answers didn't help me...
mixing joined and single table inheritance and querying for all objects - same issue..
How to mix inheritance strategies with JPA annotations and Hibernate? - mixing single_table with joined.. this is not helpful in my case..
The JPA spec does not allow you to mix strategies in an inheritance tree; it requires you to set the inheritance strategy in the root Entity. JDO is the only spec allowing mixed strategies. You may find a JPA implementation that allows it, but it is non-portable
I have an abstract entity that 4 other entities inherit from. This relationship works well, however I want to query the abstract entity so that I get all entities regardless of their types. I have no idea where to place such a method since the parent entity dao is also abstract.
EntityParent (abstract) -> EntityType1, EntityType2, EntityType3, EntityType4
DAOs look like this:
EntityParentDAO (abstract) -> EntityType1DAO, EntityType2DAO, EntityType3DAO, EntityType4DAO
TX also look like this:
EntityParentTx (abstract) -> EntityType1Tx, EntityType2Tx, EntityType3Tx, EntityType4Tx
My project structure goes as follows:
Entities -> DAO for each entity -> TX for each DAO -> Service combining several TXs
There is Service which uses all of the *TX*s that's within the scope of my project. Is this where a criteria/HQL query should be placed? That doesn't sound quite right.
For example let's say I have a Car parent entity and that I have children entities Coupe, Sedan, Minivan and so on and I want a list of cars given a property that is common to all and therefore in the entity (and it its table) Car. Where would I place this query/method given the structure I'm following?
I'm not sure I follow the transaction inheritance, but why not make the parent dao concrete and add it there? As long as the parent is an Entity, and it has the field, you can query on it. The return type will be a list of the base type, but it will be instances of the actual type.
Ex:
#Entity
#Table(name = "table")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER)
public abstract class ParentImpl implements Parent{}
#Entity
#DiscriminatorValue("1")
public class Entity1Impl extends ParentImpl {}
public interface AbstractDao<T extends Parent> {}
public interface ConcreteParentDao<Parent> {}