Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #33221

Re: Using GROUP By or @OrderColumn in JPA

From Arne Vajhøj <arne@vajhoej.dk>
Newsgroups comp.lang.java.programmer
Subject Re: Using GROUP By or @OrderColumn in JPA
Date 2015-11-28 22:44 -0500
Organization Aioe.org NNTP Server
Message-ID <n3dsba$2re$1@speranza.aioe.org> (permalink)
References <87bnai8pu7.fsf@Equus.decebal.nl> <n35lmq$mph$1@speranza.aioe.org> <87two9e0l7.fsf@Equus.decebal.nl> <n38b8u$br8$1@speranza.aioe.org>

Show all headers | View raw


On 11/26/2015 8:22 PM, Arne Vajhøj wrote:
> On 11/26/2015 1:28 AM, Cecil Westerhof wrote:
>> This was never done with SQL. They made a JPQL query that was badly
>> written. I managed to help rewrite it, so it is a bit clearer what is
>> happening. But everything was done over instant message, which is not
>> ideal. Today we will meet face to face and I hope to get a better
>> understanding of what they want and have.
>
> I would probably do one of these:
>
> 1) Let JPA retrieve all decisions but add a getLastDecision
>     method to the Estimate class. If the number of decisions
>     per estimate is small then the overhead should be
>     insignificant.
>
> 2) Don't let JPA map between estimates and decisions. Instead
>     make a getLastDecision method in Estimate class that
>     does a separate JPQL query to get the data. If the number
>     of estimate for which you need last decision is small
>     then the overhead should be insignificant.

To elaborate a bit on options and pros and cons.

Some generic data:

mysql> SELECT * FROM p;
+----+---------+
| id | descrip |
+----+---------+
|  1 | P#1     |
|  2 | P#2     |
+----+---------+
2 rows in set (0.03 sec)

mysql> SELECT * FROM c;
+----+-----+---------+
| id | pid | descrip |
+----+-----+---------+
|  1 |   1 | C#1.1   |
|  2 |   1 | C#1.2   |
|  3 |   2 | C#2.1   |
|  4 |   2 | C#2.2   |
+----+-----+---------+
4 rows in set (0.00 sec)

We want P join latest C:

P#1 : C#1.2
P#2 : C#2.2

Solution 1 - true object model:

Load all C and have a method in P to return the latest C.

	@OneToMany(mappedBy = "pid")
	public List<C1> getC() {
		return c;
	}
	public void setC(List<C1> c) {
		this.c = c;
	}
	@Transient
	public C1 getLastC() {
		C1 res = null;
		for(C1 o : c) {
			if((res == null) || (o.getId() > res.getId())) {
				res = o;
			}
		}
		return res;
	}

	List<P1> all = em.createQuery("SELECT p FROM P1 p").getResultList();
	for(P1 one : all) {
		System.out.printf("%s : %s\n", one.getDescrip(), 
one.getLastC().getDescrip());
	}

Pro's:
- this is a true in memory object/domain model
- classes are fully reusable for other queries
- nice JPA
- potentially data can be join fetched
Con's:
- load C's that are not needed for specific task

Solution 2 - manual lazy load of C's:

One to many is not mapped in JPA and P has a get that load
relevant C on demand.

	@Transient
	public C2 getC() {
		if(c == null) {
			EntityManagerFactory emf = Persistence.createEntityManagerFactory("PC");
			EntityManager em = emf.createEntityManager();
			@SuppressWarnings("unchecked")
			List<C2> onelst = em.createQuery("SELECT c FROM C2 c WHERE c.pid = 
:pid ORDER BY c.id DESC").setMaxResults(1).setParameter("pid", 
id).getResultList();
			c = onelst.get(0);
			em.close();
			emf.close();
		}
		return c;
	}

[ignore the EMF and EM parts plus the missing error handling - this
is just a SE demo app]

	@SuppressWarnings("unchecked")
	List<P2> all = em.createQuery("SELECT p FROM P2 p").getResultList();
	for(P2 one : all) {
		System.out.printf("%s : %s\n", one.getDescrip(), one.getC() != null ? 
one.getC().getDescrip() : "");
	}

Pros:
- only load C's needed
- nice JPA
Con's:
- classes are limited reusable
- data can not be join fetched

Solution 3 - non ORM style:

Normal POJO's, SQL and manual object
construction.

		@SuppressWarnings("unchecked")
		List<Object[]> allrow = em.createNativeQuery("SELECT p.id AS 
pid,p.descrip AS pdescrip,c.id AS cid,c.descrip AS cdescrip FROM p JOIN 
c ON p.id=c.pid WHERE c.id = (SELECT MAX(id) FROM c WHERE 
c.pid=p.id)").getResultList();
		List<P3> all = new ArrayList<P3>();
		for(Object[] row : allrow) {
			P3 p = new P3();
			p.setId((Integer)row[0]);
			p.setDescrip((String)row[1]);
			C3 c = new C3();
			c.setId((Integer)row[2]);
			c.setDescrip((String)row[3]);
			p.setC(c);
			all.add(p);
		}
		for(P3 one : all) {
			System.out.printf("%s : %s\n", one.getDescrip(), one.getC() != null ? 
one.getC().getDescrip() : "");
		}

[ignore whether the SQL is the optimal for the task - this
is just a SE demo app]

Pro's:
- only load C's needed
- join fetch
Con':
- classes are limited reusable (for true JPA)
- significant code
- really plain JDBC  not utilizing JPA

Solution 4 - SQL with result mapping:

As above but let JPA map query result to classes.

		@SuppressWarnings("unchecked")
		List<Object[]> allrow = em.createNativeQuery("SELECT p.id AS 
pid,p.descrip AS pdescrip,c.id AS cid,c.pid AS cpid,c.descrip AS 
cdescrip FROM p JOIN c ON p.id=c.pid WHERE c.id = (SELECT MAX(id) FROM c 
WHERE c.pid=p.id)", "PjoinCMapping").getResultList();
		List<P4> all = new ArrayList<P4>();
		for(Object[] row : allrow) {
			P4 p = (P4)row[0];
			C4 c = (C4) row[1];
			p.setC(c);
			all.add(p);
		}
		for(P4 one : all) {
			System.out.printf("%s : %s\n", one.getDescrip(), 
one.getC().getDescrip());
		}

       <sql-result-set-mapping name="PjoinCMapping">
          <entity-result entity-class="jpaproblem.sol4.P4">
              <field-result name="id" column="pid"/>
              <field-result name="descrip" column="pdescrip"/>
          </entity-result>
          <entity-result entity-class="jpaproblem.sol4.C4">
              <field-result name="id" column="cid"/>
              <field-result name="pid" column="cpid"/>
              <field-result name="descrip" column="cdescrip"/>
          </entity-result>
       </sql-result-set-mapping>

Pro's:
- only load C's needed
- join fetch
- mapping is reusable for all sorts of joins  of these two tables
Con':
- classes are limited reusable (for true JPA)
- significant configuration

Arne

Back to comp.lang.java.programmer | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Using GROUP By or @OrderColumn in JPA Cecil Westerhof <Cecil@decebal.nl> - 2015-11-25 09:07 +0100
  Re: Using GROUP By or @OrderColumn in JPA Arne Vajhøj <arne@vajhoej.dk> - 2015-11-25 20:02 -0500
    Re: Using GROUP By or @OrderColumn in JPA Cecil Westerhof <Cecil@decebal.nl> - 2015-11-26 07:28 +0100
      Re: Using GROUP By or @OrderColumn in JPA Jerry Stuckle <jstucklex@attglobal.net> - 2015-11-26 08:25 -0500
      Re: Using GROUP By or @OrderColumn in JPA Arne Vajhøj <arne@vajhoej.dk> - 2015-11-26 20:22 -0500
        Re: Using GROUP By or @OrderColumn in JPA Silvio <silvio@internet.com> - 2015-11-27 12:28 +0100
          Re: Using GROUP By or @OrderColumn in JPA Jerry Stuckle <jstucklex@attglobal.net> - 2015-11-27 09:22 -0500
            Re: Using GROUP By or @OrderColumn in JPA Silvio <silvio@internet.com> - 2015-11-27 17:42 +0100
              Re: Using GROUP By or @OrderColumn in JPA Silvio <silvio@internet.com> - 2015-11-27 17:43 +0100
                Re: Using GROUP By or @OrderColumn in JPA Martin Gregorie <martin@address-in-sig.invalid> - 2015-11-27 18:21 +0000
          Re: Using GROUP By or @OrderColumn in JPA Arne Vajhøj <arne@vajhoej.dk> - 2015-11-28 23:01 -0500
            Re: Using GROUP By or @OrderColumn in JPA Silvio <silvio@internet.com> - 2015-11-29 12:42 +0100
        Re: Using GROUP By or @OrderColumn in JPA Arne Vajhøj <arne@vajhoej.dk> - 2015-11-28 22:44 -0500
      Re: Using GROUP By or @OrderColumn in JPA Martin Gregorie <martin@address-in-sig.invalid> - 2015-11-27 11:07 +0000

csiph-web