I have currently these 2 entities:
Titular and Familiar (Family/kin/relative).
Familiar [0..*]<------>[1] Titular
These 2 classes has commons attributes of a person (firstName, lastName, birthDate....) and they are 2 kind of Affiliate
I want to unify those in one super class (generalization) Person but what I can't figure out is I should make Titular and Familiar extend Person or add Person as attribute of them.
Person also has to exists by itself (cannot be abstract) and not all Persons are Affiliates
BUT! I also need a way to establish/handle commons behaviors for Titular and Familiar.
Person [1]<------>[0..*] Titular
Person [1]<------>[0..*] Familiar
Titular [1]<------>[0..*] Familiar
So the doubt is:
public class Titular extend Person
public class Familiar extend Person {
or
public class Titular implement Affiliate {
private Person person;
public class Familiar implement Affiliate {
private Titular t;
private Person person;
or (3rd thought)
public class Person {
public abstract class Affiliate {
protected Person person;
public class Titular extends Affiliate {
The way I see it, all Affiliates are persons too (or you have exceptions to this?)! So the right hierarchy is:
Person --- Affiliate --- Titular
\- Familiar
Now, as to inheriting or having a pointer... that is called composition v/s inheritance and there are good arguments for both. The main reasons for chosing composition are
Mutable or optional relationships: Say, the owner of a car can change or a car can have no owner. A cat can not stop to be an animal and be something else.
Different Public API: While more work, composition allows you to manually forward whatever API you want to expose from your internal pointer, hiding or changing things from the "parent" as you will.
In general, you'll find inheritance makes more sense when ClassA IS-A ClassB, so you would not expect that to change nor would you want both classes to present a different API. You'll see this recommendation everywhere and it seems to fit your example like a glove.
After a few test, I had decided for Composition over inheritance.
As one of tag is "JPA", this solution has to be mapped/annotated
..and none of the possible annotations suits
#Inheritance(strategy = InheritanceType.JOINED/SINGLE_TABLE/TABLE_PER_CLASS)
If Titular and Familiar extends from Person, the ORM required a "DTYPE" column in Person, which is useless for me because no matters in how many Titular or Familiar a Person can/will become in its life, it just must be ONE register of Person.
And being an Affiliate is a "concept" or behavior, which I need it to do some polymorphic tasks, it doesn't has any persistable attribute (FOR NOW!), I will make an Interface of it.
#Entity
public class Persona {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Entity
public class Titular implements Afiliado {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JoinColumn(nullable = false)
#ManyToOne(optional = false)
private Persona persona;
#Entity
public class Familiar implements Afiliado {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JoinColumn(nullable = false)
#ManyToOne(optional = false)
private Persona persona;
#ManyToOne
private Titular titular;
public interface Afiliado {
public String getNumero();
//trick but necessary
public Persona getPersona();
//another default Java 8 implementations..
}
Stated in verbose, we want the following behavior (If I understand you correctly):
Titular is a Person who supports the functionality of an Affiliate.
Familiar is a Person who supports the functionality of an Affiliate and is associated with a Titular.
After reading these two lines enough number of times, one possible solution that seems reasonable is:
public class Titular extends Person implements Affiliate {
public class Familiar extends Person implements Affiliate {
private Titular t;
Related
I have a similar entities and I use the following approach and use a base class:
#MappedSuperclass
public abstract class Dining {
// constructors
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dining_gen")
private long id;
#Column(nullable = false)
private UUID groupUuid;
#Column(nullable = false)
private String name;
}
#Entity
#SequenceGenerator(...)
#Table(...)
public class Room extends Dining {
// constructors
}
#Entity
#SequenceGenerator(...)
#Table(...)
public class Point extends Dining {
// constructors
}
I also use a base DTO, Request, etc. for these classes. However, I am wondering until which level I should apply abstraction. Should I use a generic base repository (Dining) and extend to Room and Point repositories?
What about services? I use Interface and its implementations in my Spring Bot app. In this scene, should I create a base interface or should I also create base service implementation and extend to Room and Point services?
If there is a good example as a best or proper practice, could you suggest me pls?
I made a research about Inheritance in JPA and resources that I found uses just one superclass for each entity. But there is not an example that uses 2 or more superclass.
What about this:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = “Abstract_One”)
public abstract class AbstractOne {
#Id
protected Long id;
…
}
#Entity(name = “A”)
#DiscriminatorValue(“A”)
public class A extends AbstractOne {
#Column
private int a;
…
}
#Entity(name = “B”)
#DiscriminatorValue(“B”)
public class B extends A {
#Column
private int b;
…
}
Is it possible to do that?
If it is possible, which Inheritance Strategy allows that and gives the best data consistency?
I can imagine only the following example
#MappedSuperclass
public class A
{
...
#Id
#Column(name = "RECID")
public Long getId()
...
}
#MappedSuperclass
public class B extends A
{
...
#Column(name = "COL1")
public String getColumn1()
...
}
#Entity(name="INH_TAB1")
public class C extends B
{
...
#Column(name = "COL2")
public String getColumn2()
...
}
Also at the excellent book "Java Persistence with Hibernate" by Bauer, King, Gregory I found the following plase what can be useful in the context of this question:
6.5 Mixing inheritance strategies
You can map an entire inheritance hierarchy with the TABLE_PER_CLASS,
SINGLE_TABLE, or JOINED strategy. You can’t mix them — for example, to switch from a
table-per-class hierarchy with a discriminator to a normalized table-per-subclass
strategy. Once you’ve made a decision for an inheritance strategy, you have to stick with it. This isn’t completely true, however. By using some tricks, you can switch
the mapping strategy for a particular subclass. For example, you can map a class
hierarchy to a single table, but, for a particular subclass, switch to a separate
table with a foreign key–mapping strategy, just as with table-per-subclass.
However, I can not imagine any real case when such complex inheritance hierarchy will be required/useful and also it can affect performance.
I have a question about what would be the best practice for modeling my Java classes and how they should be related in the database. I'm using Spring-Boot and Spring-Data in the project
I have the situation containing professional Administrative, Professional Financial and Professional Developer. Each of them have specific characteristics.
So, I created a Professional class with the attibutos that are common to all employees:
Professional Class
#Entity
#Table(name = "Professional")
#Inheritance(strategy = InheritanceType.JOINED)
public class Professional {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String age;
... getters e setters
}
The other classes, extend from the professional class:
Administrative Class
#Entity
public class Administrative extends Professional {
private String attribute1;
private String attribute2;
... getters e setters
}
Financial Class
#Entity
public class Financial extends Professional {
private String attribute1;
private String attribute2;
... getters e setters
}
Developer Class
#Entity
public class Developer extends Professional {
private String attribute1;
private String attribute2;
... getters e setters
}
Is this the most appropriate way to handle this scenario? Should I use Class Composition instead of Inheritance? Could you please share examples?
Thank you
Inheritance makes more sense here. As an example, composition makes sense where an entity has another entity, e.g.
class Adult extends Person {
private List<Animal> pets; // person HAS pets (with are another class)
private ID identityCard; // person HAS an identity card
}
It wouldn't make sense here for a Person to extend either of Animal or ID because they aren't a subset of either. However, they are a child of the Person class so it makes sense to inherit.
In your case inheritance makes sense because your child classes are a subset of the Professional. You wouldn't say that a Developer has a Professional, but they are a Professional.
I faced a problem how I can create JPA entity which extends multiple base abstract classes (without creating additional table). I know there is an annotation #MappedSuperclass, but it gives an ability to create only one base class as soon as we use extends and multiple inheritance is not a Java feature.
For example, I have two bases:
#MappedSuperclass
public abstract class Authored {
#ManyToOne
private User user;
}
and
#MappedSuperclass
public abstract class Dated {
private String creationDate;
}
I expect that some of my models will extend only Authored, some -- only Dated, and some -- both.
Though it's only possible to write
#Entity
public class MyEntity extends Authored {
...
}
or
#Entity
public class MyEntity extends Dated {
...
}
Some discussions propose to inherit classes in line (e.g. Authored and AuthoredAndDated) but this seems too dirty, none of this bases logically can't extend another one.
ADDITION
I have to note that this style is supported in other frameworks like Django (due to multiple inheritance in python) so it's strange that JPA doesn't support it.
I am sorry to disappoint you, but there is no other solution than creating AuthoredAndDated as you suggested.
We faced in the same issue for our entities and went with the same procedure.
We have a
#MappedSuperclass
public class TimestampedObject {
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at")
private Date createdAt;
#UpdateTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_at")
private Date updatedAt;
}
and a
#MappedSuperclass
public class IdObject {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id", updatable = false, columnDefinition = "serial")
private Long id;
}
Thus we created a TimestampedIdObject for this purpose.
Edit:
If you find another suitable solution, it would be great if you could post it here, as we have the same issue...
You should use an #Embeddable / #Embedded for goal by replacing inheritance with composition.
First, do not use #MappedSuperClass, but use #Embeddable instead for your classes you want to share the attributes with:
#Embeddable
public class Authored {...}
#Embeddable
public class Dated {...}
In the next step your Entity should not inherit from Authored or Dated but instead get an attribute referencing them:
#Entity
public class MyEntity {
#Embedded
private Authored authored;
#Embedded
private Dated dated;
}
If you want to get behaviour out of this, where you can generically access without those new attributes, you would need to introduce an interface exposing the necessary methods.
For expample if MyEntity should be able to provide details on last updates and creation, you would introduce an interface Authorable which defines to methods to access the relevant data.
public interface Authorable { /* necessary methods */ }
MyEntity will implement this interface then:
#Entity
public class MyEntity implements Authorable {
/* previous content plus implemented mehtods from interface */
}
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;
}