3

I am a beginner when it comes to JPA and I am struggling to write the proper entity classes for my database structure.

Firstly, here are my tables:

create table article (
  id varchar(100) not null primary key,
  title varchar(255) not null
)
create table article_provider (
  providerId varchar(60) not null,
  articleId varchar(100) null,
  isOnSale BOOL NOT NULL,
  constraint article_provider_articleid_fk foreign key (articleId) references article (id) on update cascade on delete cascade
)

As you can see I have a one-to-many relationship (every article can have 0..n providers). Now when accessing articles I would also like to know, if the article is on sale by any of it's providers. For this I would use the following SQL query:

SELECT article.*, MAX(article_provider.isOnSale) AS isOnSale FROM article
LEFT JOIN article_provider ON article.id = article_provider.articleId
GROUP BY article.id

How would I best go about fetching this type of result using Hibernate/JPA?

diesieben07
  • 1,487
  • 1
  • 14
  • 25
  • article_provider looks like a join table and it looks more like many to many relationship – HRgiger Feb 09 '18 at 15:03
  • 1
    How is this many to many if `article_provider` has a singular `articleId` reference? Every `article_provider` has _one_ `article`, every `article` can have any number of `article_provider` entries. Note that `article_provider` does not denote information about the provider, it denotes information about how that provider offers that article (i.e. price, whether it's on sale, etc.). `provider` is a separate table. – diesieben07 Feb 09 '18 at 20:41

1 Answers1

0

Your query is not right -- you use attributes in SELECT clause that are not in GROUP BY clause, but for example to select Article.id + MAX(whatever) you can use something like:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Article> query = builder.createQuery(Article.class);
Root<Article> root = query.from(Article.class);
Join<Article, ArticleProvider> join = root.join(Article_.provider, JoinType.LEFT);
query.multiselect(root.get(Article_.id), builder.max(sale));
query.groupBy(root.get(Article_.id));
// query will return collection of scalar attributes (ID + Number)
Object result = entityManager.createQuery(query).getResultList()

To select exactly Article.* + MAX(sales) you would need to use the above as a subquery and join again with Article entity.

But there are simillar of examples elsewhere: How do I write a MAX query with a where clause in JPA 2.0?

EDIT:

bubak
  • 1,464
  • 1
  • 13
  • 11
  • If I group by the primary key in `article` there can only be one result for every column in the `article` table, right? So, how is `article.*` not ok then? And I don't need only the article ID, I need everything in the article table. – diesieben07 Feb 09 '18 at 20:40
  • @diesieben07 see for example http://bernardoamc.github.io/sql/2015/05/04/group-by-non-aggregate-columns/ – bubak Feb 09 '18 at 23:42
  • I am aware of the problems described in that article, but they cannot occur when grouping by the primary key, can they? – diesieben07 Feb 09 '18 at 23:57
  • you cannot reference columns in select clause that are missing in group by clause -- what is exactly what you are doing by 'article.*' – bubak Feb 10 '18 at 00:08
  • Well, I tried the query right before I posted here and it worked fine. – diesieben07 Feb 10 '18 at 00:16
  • out of curiosity -- what database are you using? in oracle similar query ends with ORA-00979 (http://www.dba-oracle.com/t_ora_00979_not_a_group_by_expression.htm) if you group by id, you can have several lines for such an id (i understand, they are probably the same in case of primary key) -- but how the database knows, what row to show you, if they are multiple without specifying another aggregate function? – bubak Feb 10 '18 at 00:26
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164865/discussion-between-bubak-and-diesieben07). – bubak Feb 10 '18 at 00:29
  • I have done some more research, and my query is actually completely fine according to newer SQL standards (SQL-99 and onwards). See these articles: http://rpbouman.blogspot.de/2007/05/debunking-group-by-myths.html and http://rpbouman.blogspot.de/2014/09/mysql-575-group-by-respects-functional.html – diesieben07 Feb 12 '18 at 14:38
  • I have answered in discussion above. – bubak Feb 13 '18 at 21:05