javaoracle-databasestored-proceduresentityquarkus

How to debug a SP response in Quarkus using EntityManager


Good afternoon, I am currently building a microservice that executes the call of an SP (Stored Procedure) in Quarkus using EntityManager and StoredProcedureQuery, the issue is that I am experiencing problems when mapping what the DB returns, there are differences (there are records that are being returned duplicated because they have the same primary key, however, the rest of the data changes) in terms of what the SP returns when executing it manually with what is returned when mapping to the list in Java, so I would like to know how I can debug from IntellijIdea what the DB returns and know why the data is being duplicated, or if you can give me ideas as to why it could be duplicated.

I add the main classes that I am using

Entity

package com.tmve.account.beans;


import lombok.Getter;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Date;

@NamedStoredProcedureQueries({
        @NamedStoredProcedureQuery(
                name = PostpaidAccount.NAME_QUERY_BUSCAR_CUENTAS_ROLES_X_DOC_IDE,
                procedureName = "PERS.PKG_COMP_CUENTAS.BUSCAR_CUENTAS_ROLES_X_DOC_ID",
                resultClasses = {PostpaidAccount.class},
                parameters = {
                        @StoredProcedureParameter(mode = ParameterMode.IN, type = String.class),
                        @StoredProcedureParameter(mode = ParameterMode.IN, type = Integer.class),
                        @StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class),
                })
})
@Getter
@Entity
@ToString
public class PostpaidAccount implements Serializable {

    public static final String NAME_QUERY_BUSCAR_CUENTAS_ROLES_X_DOC_IDE=  "BuscarCuentasRolesxDocId";
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "V_NUMERO_CUENTA")
    Long account;
    @Column(name = "V_NUM_CTA_PAGADORA")
    Long billingAccountNumber;
    @Column(name = "V_NUM_CTA_DIG_VERI")
    Long billingAccountNumberValidators;
    @Column(name = "V_TIPO_CUENTA")
    String accountType;
    @Column(name = "V_ESTADO")
    String accountStatus;
    @Column(name = "V_NOMBRE_ESTADO")
    String accountStatusDescription;
    @Column(name = "V_ID_PRODUCTO")
    Integer productoId;
    @Column(name = "NOMBRE_PRODUCTO")
    String productName;
    @Column(name = "FECHA_INICIO_PROD")
    Date customerSince;
    @Column(name = "NOMBRES")
    String accountHolder;
    @Column(name = "V_TIPO_RELACION")
    String relationshipType;
    @Column(name = "V_PLATAF")
    int platformId;
    @Column(name = "V_IDENTIFICADOR")
    String identifier;
    @Column(name = "NOMBRE_AREA")
    String marketName;
}

Repoository

In this class I would like to know what I can implement or how I can debug what the DB returns once the following line is executed:

storedProcedureQuery.execute();

package com.tmve.account.repositoty.impl;

import com.tmve.account.beans.PostpaidAccount;
import com.tmve.account.repositoty.IFindPostpaidAccountByDocumentRepository;
import lombok.extern.slf4j.Slf4j;


import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.StoredProcedureQuery;
import java.util.List;

@Slf4j
@Singleton
public class FindPostpaidAccountByDocumentRepository implements IFindPostpaidAccountByDocumentRepository {

    @Inject
    EntityManager entityManager;

    @Override
    public List<PostpaidAccount> getPostpaidAccount(String documentType, String documentNumber) {

        StoredProcedureQuery storedProcedureQuery=entityManager
                .createNamedStoredProcedureQuery("BuscarCuentasRolesxDocId");
        storedProcedureQuery.setParameter(1,documentNumber);
        storedProcedureQuery.setParameter(2,Integer.parseInt(documentType));

        storedProcedureQuery.execute();
        List<PostpaidAccount> result= storedProcedureQuery.getResultList();
        return result;

    }
}

This is how logs are displayed when debugging in IntelliJ Idea:

enter image description here

And according to what the DB returns, the records should look like this:

enter image description here

As we can see, the records are being duplicated and I don't understand why. Could it have something to do with the approach of using the EntityManager?


Solution

  • I would imagine that by asking Hibernate ORM to map results to the type PostpaidAccount -- which is an entity type -- you are effectively asking those results to be managed in the Hibernate ORM Session, which implies there can only be one instance of each entity with a given ID ("primary key").

    So, duplicate records are just ignored, and replaced with the first record found in your result set.

    The core of your problem is that you're trying to have two entity instances with the same ID but different values. That doesn't make sense.

    Either:

    1. Your mapping is incorrect, and V_ID_PRODUCTO (and maybe others?) should be part of the ID of your entity. The ID can be composite (see @EmbeddedId) but must be unique.
    2. This is some special use case -- for example audit/history -- that is supposed to return two "versions" of each PostPaidAccount -- for examples at different points in time -- in which case you should not use PostpaidAccount as your result type, but rather a dedicated class that is not an entity type -- for example PostpaidAccountDto.

    Regarding #2, there might be ways to tell Hibernate ORM "don't treat the PostpaidAccount type as an entity type for this query", but I don't know them, and in any case that reeks of bad practice to me: should a PostpaidAccount instance end up in another service that expects managed entities, you're bound to see unpredictable behavior because the values in that instance do not necessarily reflect the state of the database.