I have designed the entities in my application to follow the Hibernate's inheritance strategy Inheritance.JOINED
.
The base abstract class is UserTable
and the concrete derived classes are ClientTable
and the OwnerTable
.
The thing that I want to achieve is to have a single repository in which I could find
any UserTable
(both ClientTable
and OwnerTable
) by the Id
or Email
. The important requirement is that they can be cast to the correct type once they are fetched, and that they carry their specific fields (and not just the ones inherited from UserTable
).
Equally important, I should be able to persist those entities through the same repository, ie. repository.save(clientTable)
.
So something like this should be possible:
UserTableRepository repository = // ...
int clientId = 3;
int ownerId = 5;
ClientTable clientTable = (ClientTable) repository.findByUserId(clientId);
OwnerTable clientTable = (OwnerTable) repository.findByUserId(ownerId);
clientTable = (ClientTable) repository.findByEmail(clientEmail);
ownerTable = (OwnerTable) repository.findByEmail(ownerEmail);
My entities look like this.
UserTable.java
@Entity
@Table(name = "USER")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class UserTable implements Serializable {
@Column(name = "USER_ID", nullable = false)
private Long userId;
@EmbeddedId
private UserTablePK userTablePK;
@Column(name = "PASSWORD", nullable = false, length = 512)
private String password;
@Column(name = "FIRSTNAME", nullable = false, length = 256)
private String firstName;
// get, set
}
.. and a primary key
UserTablePK.java
@Embeddable
public class UserTablePK implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "EMAIL", nullable = false, length = 256)
private String email;
public UserTablePK() {
}
public UserTablePK(String email) {
this.email = email;
}
// get, set
}
ClientTable.java
@Entity
@Table(name = "CLIENT")
public class ClientTable extends UserTable implements Serializable {
@Column(name = "SHOPING_POWER")
private Integer shoppingPower;
@Column(name = "SHOPPING_FREQUENCY")
private Integer shoppingFreq;
// get, set
}
OwnerTable.java
@Entity
@Table(name = "OWNER")
public class OwnerTable extends UserTable implements Serializable {
@Column(name = "EFFICIENCY")
private String efficiency;
@Column(name = "SALARAY")
private Integer;
// get, set
}
Now once the entities are set, I need to write a repository that would act like described above, and here is where I need some help. I was thinking to write something like this.
UserTableRepository.java
@Repository
public interface UserTableRepository extends CrudRepository<UserTable, UserTablePK> {
@Query("SELECT e FROM UserTable e WHERE e.userTablePK.email = ?1")
public UserTable findByEmail(String email); // if owner email, retrieve OwnerTable; if client email, retrieve ClientTable instance
@Query("SELECT e FROM UserTable e WHERE e.userId = ?1")
public UserTable findByUserId(Long userId); // if owner id, retrieve OwnerTable; if client id, retrieve ClientTable instance
}
I didn't actually try this yet, because I want to check if this is even the right route to take, but: I am rather skeptical that this Query
would work. Because in order to retrieve the whole subclass object, some kind of JOIN should be used, and the problem is that I can't explicitly say ie. JOIN ClientTable
because then I would not be able to fetch any OwnerTable
entities.
How can I achieve that I can fetch both subclasses from the same repository?
Also, the requirement is to be able to fetch for the specific subclass. So something like:
List<ClientTable> clients = repository.findAllClients();
Is that possible using the same repository, or should I write repositories specific for subclasses? For example.
@Repository
public interface ClientTableRepository extends CrudRepository<ClientTable, ClientTablePK> {
// empty
}
... and then call them like:
ClientTableRepository repository = // ...
List<ClientTable> clients = repository.findAll();
Would that be enough for the JPA to determine how to find all the instances of just a specific subclass?
What you want to achieve is exactly how inheritance in JPA works.
So your queries are perfectly fine and you will have instances of the subclasses in the result list.
Read more about JPA inheritance in one of my blog posts:
https://72.services/inheritance-in-jpa/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With