JPA: common entity used by many other entity classes - java

I have searched quite a bit through other SO questions without luck, possibly due to me using the incorrect search terms.
I would like to create an entity (Note), that can be "attached" to any other Entity in our inheritance tree.
eg:
#Entity
class Note extends AbstractEntity {
String title
String message;
AbstractEntity relatedItem;
}
#Entity
class EntityOne extends AbstractEntity {
}
#Entity
class EntityTwo extends AbstractEntity {
}
I know that I could do the following:
#Entity
class Note extends AbstractEntity {
String title
String message;
}
#Entity
class EntityOne extends AbstractEntity {
List<Note> notes;
}
#Entity
class EntityTwo extends AbstractEntity {
List<Note> notes;
}
but this will then result in tables like:
Note - ID, title, message
EntityOne_Note - entityOne_ID, note_ID
EntityTwo_Note - entityTwo_ID, note_ID
and requires me to update the entities if we wish to add note support to them.
For some reason it just feels better to have a table like:
Note - ID, title, message, relatedItem_ID, relatedItem_DTYPE
I dont even mind a single extra table:
Note - ID, title, message
AbstractEntity_Note - relatedItem_ID, relatedItem_DTYPE, note_ID
thoughts?

It depends on how many relatedItem_DTYPE you have, if they are few (for example 2) you can use an approach like this
#Entity
class Note extends AbstractEntity{
public String title
public String message;
#ManyToOne
EntityOne e1;
#ManyToOne
EntityTwo e2;
}
If you wish to have the references to the notes in Entities classes, just add a field to keep trace of the reverse relation.
You will end up to classes like these:
#Entity
public class EntityOne{
...
#OneToMany(mappedBy="e1")
public List<Note> notes;
}
#Entity
public class EntityTwo{
...
#OneToMany(mappedBy="e2")
public List<Note> notes;
}
Or you can try to create the inheritance using the InheritanceType.TABLE_PER_CLASS and see how Hibernate handle that :D.
By the way keep in mind that just saving the couple relatedItem_ID, relatedItem_DTYPE means that a note can belongs only to one instance of a particular type.

Related

Hibernate extending entity for read with additional joins

I have an entity that corresponds to some table in DB
#Entity
#Table
public class MyEntity {
#Id
private Long id;
#Column
private String description;
#OneToMany
private List<Foo> foos;
...
//getters setters
...
}
And I would like to extend that entity for read-only and have additional joins to another table. I need this joins only in one case for specific read user-case:
#Entity
public class ExtendedEntity extends MyEntity {
#ManyToMany(fetch = FetchType.EAGER)
private List<Bar> bars;
}
Just using extensions will create a discriminator column in DB, which I don't need since I'm using the ExtendedEntity only for the read. I found I hack with using #DiscriminatorFormula that will be resolved to the same Integer value like this:
#DiscriminatorFormula("0")
#DiscriminatorValue("0")
public class MyEntity
#DiscriminatorValue("00")
public class ExtendedEntity extends MyEntity
But this really looks like a hack. With using #MappedSuperclass I cannot have associations, but this is the main reason I need to extend my entity.
What other options do I have and what are the best practices for this use-case?

Avoid JPA abstract class extra tables

I'm using JPA JOINED inheritance strategy with 3 abstract classes and 2 concrete.
Like this (code reduced for example purpose):
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
abstract class Employee {
#Id
private Long id;
private String firstName;
private String secondName;
}
#Entity
abstract class ProjectManager extends Employee {
#OneToMany(mappedBy="manager")
private List<Developer> developers;
}
#Entity
abstract class Developer extends Employee {
#ManyToOne
#JoinColumn(name="project_manager_id")
private ProjectManager manager;
}
#Entity
class JavaProjectManager extends ProjectManager {
private String someCustomProperty;
}
#Entity
class JavaDeveloper extends Developer {
private String skill;
}
This way, JPA creates 5 tables. But one of this tables, abstract ProjectManager it is empty. I mean, ProjectManager table only have ID column due to inheritance strategy.
My question is: how I can avoid this extra table for ProjectManager abstract class but keeping the same hierarchy of classes ?
I could not remove #Entity on ProjectManager class because I still need bidirectional relationship with Developer class.
Edit:
Also, I don't want move developers OneToMany from ProjectManager to JavaProjectManager, because I have more classes that extends from ProjectManager and need to have developers.
InheritanceType.TABLE_PER_CLASS does exactly what you want.
This type only creates/uses tables for non-abstract tables.
Read more about the various types here:
https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/

JPA discriminator undesired

I know there are several questions on this argument, but I think mine is a bit different.
I'm trying to use JPA notation instead of XML mapping. In my queries always there's an undesired dtype column, and I don't want to use neither discriminator column and formula.
I have four classes as follow:
The first named ObjectUUID. All classes extend this super class.
This class is used only to define id field, as follow:
#MappedSuperclass
public class ObjectUUID {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
protected String id;
// getter and setter and other static methods
}
Then I have another class, named TrackSys where I define other fields (as insert date and update date) as follow:
#MappedSuperclass
public class TrackSys extends ObjectUUID{
#Column(name="dt_ins")
private CustomCalendar dtInsert;
#Column(name="dt_upd")
private CustomCalendar dtUpdate;
// getter and setter
}
the third and the forth classes are beans mapped on DB, as follow:
#Entity
#Table(name="patient")
public class PatientUUID extends TrackSys {
}
#Entity
#Table(name="patient")
public class Patient extends PatientUUID {
#Column(name="surname")
private String surname;
#Column(name="name")
private String name;
#Column(name="cf")
private String cf;
// getter and setter
}
I define a repository to query my patient table, as follow:
public interface PatientRepository extends JpaRepository<Patient, Long> {
List<Patient> findBySurname(String surname);
}
When my Patient query runs, the generated SQL is the follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.dtype='Patient'
and patient0_.surname=?
Now...
I don't want dtype column and I don't want to use discriminator formula.
With the XML mapping this is possible without particular properties to specify.
With JPA annotation I try in order:
Use #Inheritance(strategy = InheritanceType.SINGLE_TABLE) but dtype is always present
Use #Inheritance(strategy = InheritanceType.JOINED) but dtype is always present
Now, my feeling versus dtype is only hate, how can I get this simple query, as follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.surname=?

The best way to extend an #Entity when the subclass has just a #Transient field besides

I have a superclass that is an #Entity, something like this one:
#Entity
#Table(name = "utente")
public class Utente implements Serializable{
...
}
The subclass has just a #Transient field besides:
#Entity
public class UtenteSub extends Utente{
#Transient
private String newField;
}
To make it work, I should add #DiscriminatorValue, #Inheritance and add a field on the table.
This is a lot of work to do, taking into account that all I need in the subclass is just a #Transient field (I need it to "check" the object Utente after its "submission" in a form).
Is there a better and easier way to extend the #Entity in my scenario?
Thank you.
You could try creating an abstract base class UtenteBase:
#MappedSuperClass
public abstract class UtenteBase implements Serializable
{
//all mapped columns go here
}
All your mapped columns which were in Utente before are now in this class.
You can then extend this class with your two above mentioned classes:
#Entity
#Table(name = "utente")
public class Utente extends UtenteBase
{
public Utente {}
}
#Entity
#Table(name = "utente")
public class UtenteSub extends UtenteBase
{
#Transient
private String newField;
}
The class Utente is the concrete implementation class and is used for the communication with the database.
Both classes are in the same inheritance tree and you don't need to add a DiscriminatorValue and change the table.

Mapping 1 table to multiple classes in JPA

I want to achieve something like this:
#Entity
#Table(name = "beer")
public class Beer {
#Id Long id;
String brand;
String name;
}
#Entity
public class BeerWithIngredients extends Beer {
#OneToMany(mappedBy="beer")
List<BeerIngredient> ingredients;
}
#Entity
public class BeerIngredient {
#Id Long id;
// .. whatever fields
#ManyToOne
#JoinColumn(name = "beer_id")
BeerWithIngredient beer;
}
Physically, all beer data is in one table, but I want to split it into more entities.
Please note that:
I would not like to use discriminator column in the database
There isn't a column that I could use for #DiscriminatorFormula
I do not want to embed Beer inside BeerWithIngredients, because it essentially is not a composition, but proper inheritance
Is there a way of achieving this with JPA (Hibernate)? Right now it complains about missing discriminator column, that I don't plan to provide.
Introduce a new super class RootBeer with all common beer properties. Annotate this class with MappedSuperClass. Make Beer and BeerWithIngredients inherit from RootBeer and annotate them with Entity as well as Table(name="beer").
For an example check this.

Categories

Resources