es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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í:
enter image description here

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.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una solución es utilizar un método personalizado @PrePersist en la clase abstracta Vehicle para establecer la propiedad tenantId en tanto la tabla principal Vehicle como en la tabla secundaria (es decir, Car o Plane). Aquí tienes un ejemplo:

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    abstract class Vehicle(
        var tenantId: Int,
        var title: String
    ) {
        @PrePersist
        fun prePersist() {
            // Establecer tenantId en la tabla principal
            this.tenantId = tenantId
    
            // Establecer tenantId en la tabla secundaria
            if (this is Car) {
                this.tenantId = tenantId
            } else if (this is Plane) {
                this.tenantId = tenantId
            }
        }
    }
    

    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 o Plane) para establecer la propiedad tenantId, 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 propiedad tenantId heredada del padre. Por ejemplo:

    @Entity
    class Car(
        tenantId: Int,
        title: String
    ) : Vehicle(tenantId, title) {
        ...
    }
    
    @Entity
    @AttributeOverride(
        name = "tenantId",
        column = Column(name = "tenant_id", nullable = false)
    )
    class Car(
        tenantId: Int,
        title: String
    ) : Vehicle(tenantId, title) {
        ...
    }
    

    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 propiedad tenantId en la clase secundaria, lo cual puede no ser ideal desde una perspectiva de diseño.

Comments are closed.