Implementando tablas de bases de datos jerárquicas con InheritanceType.JOINED y una columna ‘tenant_id’ en cada tabla.
Estoy tratando de implementar una estructura jerárquica utilizando el enfoque de InheritanceType.JOINED
para almacenar datos en tablas jerárquicas de la base de datos. Una limitación es que en nuestra solución multiinquilino, una columna tenant_id
debe estar presente en todas las tablas (por motivos de seguridad y exportación legal), aunque en algunos casos esto sea redundante. Este requisito está fijo.
La cuestión es que al insertar datos, la consulta que Hibernate genera no rellena el tenant_id
en la tabla de padre e hijo, lo que causa un error de restricción.
Las tablas en la base de datos se verían así:
Código para la entidad de vehículo abstracta:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
abstract class Vehicle(
var tenantId: Int,
var title: String
)
Entidad de coche:
@Entity
class Car(
override var tenantId: Int,
override var title: String,
) : Vehicle(tenantId, title) {
var numberOfDoors: Int
}
Entidad de avión:
@Entity
class Plane(
override var tenantId: Int,
override var title: String,
) : Vehicle(tenantId, title) {
var numberOfPropellers: Int
}
Al insertar un nuevo coche en la base de datos, Hibernate genera 2 consultas, donde el tenant_id
solo se agrega a la tabla abstracta Vehicle:
insert into vehicle (tenant_id, title) values (?, ?)
insert into car (id, number_of_doors) values (?, ?)
¿Hay alguna forma de indicarle a Hibernate que rellene la columna en ambas tablas?
Una solución que encontré es implementar una variable de “segundo” tenantId
en la clase y especificar una columna explícitamente de la siguiente manera:
@Column(name = "tenant_id")
private val _tenantId: Int = tenantId
Pero no es muy limpio y sería bueno tener una solución más elegante.
davy.ai
Una solución es utilizar un método personalizado
@PrePersist
en la clase abstractaVehicle
para establecer la propiedadtenantId
en tanto la tabla principalVehicle
como en la tabla secundaria (es decir,Car
oPlane
). Aquí tienes un ejemplo:Este método será llamado automáticamente por Hibernate antes de persistir un nuevo objeto en la base de datos y garantizará que la propiedad
tenantId
esté establecida en ambas tablas. Ten en cuenta que este enfoque requiere comprobar explícitamente el tipo de entidad (Car
oPlane
) para establecer la propiedadtenantId
, por lo que puede no ser escalable si tienes muchas subclases.Otro enfoque es utilizar la anotación
@AttributeOverride
en la entidad secundaria para sobrescribir la propiedadtenantId
heredada del padre. Por ejemplo:Esto hará que Hibernate genere una consulta que establece explícitamente la columna
tenant_id
en ambas tablas, tanto principal como secundaria. Ten en cuenta que este enfoque también requiere duplicar la propiedadtenantId
en la clase secundaria, lo cual puede no ser ideal desde una perspectiva de diseño.