1

I have an entity to map historic data on a system.

@Entity
@Table(name = "historicsview")
@XmlRootElement
public class ElementsHistorical implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "historicalid")
    private Long historicalId;

    @Basic(optional = false)
    @Column(name = "historicdate")
    private Date historicDate;

    @Basic(optional = false)
    @Column(name = "value")
    private double value;

    @Basic(optional = false)
    @Column(name = "code")
    private int code;

    @Basic(optional = false)
    @Column(name = "subtype")
    private int subType;

    @Basic(optional = false)
    @Column(name = "subcode")
    private int subCode;        

    @Basic(optional = false)
    @Column(name = "uniquecode", unique=true)
    private String uniqueCode;

    @JoinColumn(name = "elementid", referencedColumnName = "elementid")
    @ManyToOne(optional = false)
    private Elements element;
    .
    .
    .
}

To avoid a huge historic table, there's a trigger in database for implementing the table partition depending on historic date, so there's a copy of the table for every month. When I need to obtain the data, I need to join the tables depending on the dates provided, so the system creates a query of this kind:

select * from 
(select * from elementshistorical_201905 
where historicdate >= TO_TIMESTAMP('20190502 00:00:00', 'yyyyMMdd hh24:mi:ss') 
union 
select * from demeter.elementshistorical_201906 where historicdate <= TO_TIMESTAMP('20190606 23:59:59', 'yyyyMMdd hh24:mi:ss')) 
as foo where ((subcode=2 and (subtype=2 or subtype=8)) or code=100) and elementid in (16290) 
order by historicdate asc

I use createNativeQuery to obtain the result of this query, something like this:

public List<ElementsHistorical> executeSqlQueryHistory(String query) {
    Session session = null;
    List<ElementsHistorical> result;
    try { 
        session = SessionUtil.getSession();
        result = session.createNativeQuery(query).addEntity(ElementsHistorical.class).getResultList();
        return result;
    }catch(Exception e) {
        e.printStackTrace();
        return null;
    }finally {
        session.clear();
        session.close();            
    }

}

The problem with this is it doesn't always show exactly the same result that I get when I execute the query in database, instead, sometimes the result shows some repeated registers instead of the originals. However, the number of register is the same in both cases. For the tests I made, it seems that this starts to happen when the number of returned registers exceed about 4200, so this could be a memory management problem. Notice that for every ElementsHistorical, I need the related Element too. If I don't add the entity to the query and I treat the result as a List<Object[]>, the results are fine and doesn't show this "corrupted" registers, but I can't use this approach because then I would need to get every Element individually from each ElementsHistorical, and that would be terrible in terms of performance.

Anyone thinks that this could be a memory management problem too? How could I solve this?

Juan
  • 1,949
  • 1
  • 15
  • 22
  • I am not entirely sure, that it will help, but you can specify entity in createNativeQuery method like this session.createNativeQuery(query, ElementsHistorical.class). It might do the trick. Also, I think, that addEntity() method is not for result mapping, but for quey manipulation. You could further test it by configuring Hibernate to show sent queries and checking, if your query is somehow changed – Stas Shafeev Jun 28 '19 at 12:34
  • You select a lot of records. What do you want to do with them after selecting? Maybe Hibernate is not a good solution for your use case. – Simon Martinelli Jun 28 '19 at 12:42
  • @StasShafeev session.createNativeQuery().addEntity() is the same as entityManager.createNativeQuery with the entity class. So this will not help – Simon Martinelli Jun 28 '19 at 12:43
  • @SimonMartinelli After retrieving the data, I have to iterate over it and prepare the result to return it in the service response. I think I'll have to retrieve the data without mapping to target class and make the join afterwards by code to skip what it seems to be a Hibernate limitation – Juan Jul 02 '19 at 06:47
  • 1
    I'm sure the "prepare the result" could be done entirely on the database side. This is much faster than sending all the data to the app server. If you provide some more information about the requirements it would be easier to help you – Simon Martinelli Jul 02 '19 at 06:55
  • @SimonMartinelli There are several services using this data, depending on the service and the parameters provided, the server has to implement different calculations, being some of them a bit complex algorithmically. Probably I could implement every case for every service through a quite complex sql query, but as the slowness in the response is not a problem (because it's not), I prefer to get the "raw" data from database and let the services code do the hard job – Juan Jul 03 '19 at 08:06

0 Answers0