I created the tables Person, PersonExtra, PersonBasic, etc. in my database with the superclass Person and subclasses PersonExtra and PersonBasic.
@Entity
@Table(name = "person")
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
@Id
@Column(name = "id", nullable = false, unique = true, length = 20)
private String id;
private String name;
private String lastname;
// ...
}
@Entity
@PrimaryKeyJoinColumn(name = "extra_id")
public class PersonExtra extends Person {
private String code;
private String subject;
// ...
}
@Entity
@PrimaryKeyJoinColumn(name = "basic_id")
public class PersonBasic extends Person {
private String range;
}
If I create a Person first and then try to create a PersonExtra with an existing Person's ID, I get a duplicate ID error because it tries to persist both Person and PersonExtra. It seems like a person can only have one unique type and can only be created through the subclass.
- I would like a person to be able to be both a PersonExtra and a PersonBasic at the same time.
When I was modeling the database, it seemed better. I had the idea of using something like inheritance in the database, which could be easier to map.
How can I structure my JPA entities so different subclasses (PersonExtra and PersonBasic) can be created with the same id as the superclass (Person)?
I was thinking that maybe creating One to One relations like Person with PersonExtra and Person with PersonBasic could work.
I liked the idea of having inheritance here but, seems is it not possible in this situation?I was considering using the MappedSuperclass annotation, but isn't that just for an abstract class when the entity isn't created in the database?
Or maybe should I modify the database and create a one-to-many relationship with roles? Part of me thinks that some of the database semantics could be lost, and implementing the logic later could be complicated.
I'm new to this and could be wrong about all of this.
-
Java inheritance question for you - how can a Person be both a PersonExtra AND a PersonBasic at the same time. If you can't do it with java inheritance, JPA inheritance can't either. You want roles, where a Person can have the 'basic' and 'extra' role or data added in at the same time, not inheritanceChris– Chris2025年10月22日 18:31:28 +00:00Commented Oct 22 at 18:31
2 Answers 2
If I create a Person first and then try to create a PersonExtra with an existing Person's ID, I get a duplicate ID error because it tries to persist both Person and PersonExtra.
Of course it does. If you instantiate an object whose class is Person, then it's class is not PersonExtra or PersonBasic. If you instantiate an object whose class is PersonExtra then its class is not Person or PersonBasic, notwithstanding that you can assign a reference to it to a variable of type Person. Therefore, your Person object and your PersonExtra object cannot be either the same or equivalent. It follows that if they are persisted then they must have distinct persistent identities.
It seems like a person can only have one unique type
An object can have only one class, established when the object is created and remaining the same throughout its lifetime. This is a fundamental characteristic of Java's OO model. References to an object can be consistent with more than one type through polymorphism, this is a separate characteristic of Java's OO model. JPA works with and within Java's OO model.
and can only be created through the subclass.
Sort of. If you want an object whose class is PersonExtra then you need to create it as a PersonExtra. It then will not be a PersonBasic in any sense. It will function as Person in a polymorphic sense, and have all the properties of any Person, but its object identity is inextricably tied to having class PersonExtra.
If you persist such an object then the fact that its class is PersonExtra (and not any other) is among the details to be persisted, subject to later retrieval.
I would like a person to be able to be both a PersonExtra and a PersonBasic at the same time.
That is impossible -- inconsistent with Java's OO model -- as long as PersonExtra and PersonBasic are class types, with neither being a subtype of the other. This is not even a matter of JPA.
If every PersonExtra should also be a PersonBasic then PersonExtra should extend PersonBasic instead of extending Person directly. And if you don't need to support entities that are Persons but not PersonBasics, then you should probably combine those two into a single class.
You could also consider whether you may be looking for composition instead of inheritance. That is, maybe you want Persons to have PersonExtraDetails instead of being PersonExtras. That would be modeled via (mapped) relationships, not inheritance. For example:
@Entity
public class Person {
@Id
private String id;
private String name;
private String lastname;
@OneToOne(mappedBy="person", optional=true)
private PersonBasicDetails basicDetails;
@OneToOne(mappedBy="person", optional=true)
private PersonExtraDetails extraDetails;
// ...
}
@Entity
public class PersonExtraDetails {
@Id
private Integer id;
private String code;
private String subject;
@OneToOne
private Person person;
}
@Entity
public class PersonBasicDetails {
@Id
Integer id;
private String range;
@OneToOne
private Person person;
}
How can I structure my JPA entities so different subclasses (PersonExtra and PersonBasic) can be created with the same id as the superclass (Person)?
You can't. I'm uncertain where your mental model of this is failing you, but I suspect that you may be looking at this the wrong way around, maybe as classes being Java-side proxies for database tables. It's harder to come at this from the database side than it is to come from the Java side, and if you're starting with a database schema then you almost never are looking for polymorphic entities on the Java side.
- I was thinking that maybe creating One to One relations like Person with PersonExtra and Person with PersonBasic could work.
Indeed it could, as described above. Note well that this dispenses with the polymorphism.
- I liked the idea of having inheritance here but, seems is it not possible in this situation?
It's unclear what you liked about polymorphism for this problem, and it's unclear whether that could be made to work for you (many of the primary considerations are discussed above). I would advise you, however, that entity polymorphism is messy, and even pure-Java polymorphism tends to be overused.
- I was considering using the MappedSuperclass annotation, but isn't that just for an abstract class when the entity isn't created in the database?
A mapped superclass does not need to be abstract, but if Person were a mapped superclass instead of an entity class then objects whose class was exactly Person would not be entities. They could not be persisted in the database.
- Or maybe should I modify the database and create a one-to-many relationship with roles? Part of me thinks that some of the database semantics could be lost, and implementing the logic later could be complicated.
It's unclear to me how what you've presented would map to roles, or how a model of it would differ from the one-to-one relationships you're contemplating, but possibly that would make sense. I'm uncertain what "database semantics" you fear losing, but I think that's an issue of how you implement the details.
I'm new to this and could be wrong about all of this.
How best to model your data is a non-trivial problem, both in Java and in the database. There are often multiple viable options with different tradeoffs. When I have the freedom to design the database de novo, I tend to prefer starting on the Java side, focusing on how the entities will be used there, what their significance is, and how they are related to each other. A clean, well-factored design on that side tends to admit clean, well-normalized database designs. Which you may even be able to generate automagically from the annotated entity classes.
Comments
Take a look at Blaze Persistence entity view
But as for me that approach will lead to some complexity and cause errors
Comments
Explore related questions
See similar questions with these tags.