--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
And so it goes. Because a join will produce records with duplicated information for the objects in one-to-many relationships, I'll have to have this bulky logic for detecting when an instance changes, correct? But that is so tedious!!
I could instead do multiple queries to create the instances as I walk the graph---but isn't that less efficient and not atomic?
SELECT * FROM AUTHOR WHERE [some criteria]
SELECT * FROM BOOK WHERE AUTHOR_ID IN (...)
SELECT * FROM BOOK WHERE AUTHOR_ID IN (SELECT ID FROM AUTHOR WHERE [some criteria])
What does jOOQ expect us to do to retrieve instance graphs in an efficient way?
--
Hi, Lukas. I'm not sure you understood what I meant by "duplicate information",
and what I meant by "multiple queries... less efficient".
I'm no SQL expert, so if I'm off base here let me know. But let me break it down.
Let's say I have a BookManager interface with method getBooks(). (Assume also for the moment that authors are also objects, and that no book has the same author---that more accurately describes my particular domain model.)
Conceptually that's straightforward:
List<Book> books=new ArrayList<Book>();
Cursor<BookRecord> bookCursor=dslContext.select().from(BOOK).fetchLazy;
while(bookCursor.hasNext()) {
BookRecord bookRecord=bookCursor.fetchOne()
Book book=new Book(bookRecord.getIsbn());
book.setTitle(bookRecord.getTitle());
...
Cursor<AuthorRecord> authorCursor=dslContext.select().from(AUTHOR).where(AUTHOR.BOOK).EQUALS(bookRecord.getKey()).fetchLazy();
while(authorCursor.hasNext()) {
AuthorRecord authorRecord=authorCursor.fetchOne()
Author author=new Author(authorRecord.getURI());
author.setFirstName(authorRecord.getFirstName());
...
book.add(author);
}
books.add(book);
}
But look at all those queries. Wouldn't it be more efficient to do a join?
Cursor<Record> joinCursor=dslContext.select().from(AUTHOR).join(AUTHOR).onKey().fetchLazy();
But doesn't that mean that in the resulting "table" I'll have multiple author rows for each book, with the book information repeated in each one? I'll have to do something like this:
Book book=null;
while(joinCursor.hasNext()) {
Record record=joinCursor.fetchOne();
if(book==null || !book.getISBN().equals(record.getValue(AUTHOR.ISBN))) {
book=new Book(record.getValue(AUTHOR.ISBN)
book.setTitle(record.getValue(BOOK.TITLE)
...
books.add(book);
}
Author author=new Author(record.getValue(AUTHOR.URI));
author.setFirstName(authorRecord.getValue(AUTHOR.FIRST_NAME);
...
book.add(author);
}
And imagine if the instance hierarchy is three layers down---all that ugly logic to see if we've moved to a new row for which we've changed the current parent entity we're on for each level. Is there an easier way?
2014-07-01 16:57 GMT+02:00 Garret Wilson <gar...@globalmentor.com>:
Hi, Lukas. I'm not sure you understood what I meant by "duplicate information",I'm pretty sure I did: You're repeating "parent" (e.g. author) record data for each "child" (e.g. book)and what I meant by "multiple queries... less efficient".Hmm, what could you mean other than N+1 querying? :)
... You have these options from my point of view:
1. Use joins and implement that grouping yourself, but factor out common parts. Right now, you have a lot of redundant logic because you're explicitly tying stuff to the AUTHOR / BOOK relation. I'm sure there are elements that can be factored out generically. jOOQ provides you with foreign key meta information
2. Use joins and use jOOQ's existing Result.intoGroups() methods. It'll help doing the "grouping" (which you currently do manually, and iteratively)
3. Use several queries instead of joins, but don't fetch each author for each book. Fetch all books first, and then fetch *ALL* authors for *ALL* books
Thanks for all the links. I'll do some more research and see where that gets me.
Garret
On Wednesday, July 2, 2014 11:42:40 PM UTC-7, Lukas Eder wrote:2014-07-01 16:57 GMT+02:00 Garret Wilson <gar...@globalmentor.com>:
Hi, Lukas. I'm not sure you understood what I meant by "duplicate information",I'm pretty sure I did: You're repeating "parent" (e.g. author) record data for each "child" (e.g. book)and what I meant by "multiple queries... less efficient".Hmm, what could you mean other than N+1 querying? :)
Ah, pardon me, so you did understand. :) I had assumed that there must be a nice and tidy jOOQ solution, and simply I must not have been explaining myself clearly. I see now that this is a larger, common issue---this is why people use Hibernate, monster that it is.
... You have these options from my point of view:1. Use joins and implement that grouping yourself, but factor out common parts. Right now, you have a lot of redundant logic because you're explicitly tying stuff to the AUTHOR / BOOK relation. I'm sure there are elements that can be factored out generically. jOOQ provides you with foreign key meta information
Yeah, I can definitely refactor some of the stuff above. I was just looking for some help from jOOQ.
2. Use joins and use jOOQ's existing Result.intoGroups() methods. It'll help doing the "grouping" (which you currently do manually, and iteratively)
That's interesting, but from a cursory examination (pardon the unintentional pun)
it doesn't seem to support cursors,
meaning I'm going to get a humongous map of all those records, each of them with duplicate, duplicate, duplicate information for each of the items in the parent relationship.
// With Java collectionsMap<AuthorRecord, List<BookRecord>>// With jOOQ RecordsResult<Record2<AuthorRecord, Result<BookRecord>>>
3. Use several queries instead of joins, but don't fetch each author for each book. Fetch all books first, and then fetch *ALL* authors for *ALL* books
Yes, that would be cleaner, but I would guess that's not as efficient as a join. (I am not an SQL query expert.)
The "N+1 problem" seems to be two separate issues:
- How to nicely map stuff from joins into objects. This is where Hibernate is light years ahead, I guess. But I would have thought that jOOQ would give me some utilities to help with this. You did give some links to some mappers, which I will look into, but I didn't see any examples offhand.
- How to efficiently query data for a hierarchy of objects. From reading a tiny bit, this seems like a general problem of relational databases, one that Hibernate may not have solved, either.
Thanks for all the links. I'll do some more research and see where that gets me.
Ah, pardon me, so you did understand. :) I had assumed that there must be a nice and tidy jOOQ solution, and simply I must not have been explaining myself clearly. I see now that this is a larger, common issue---this is why people use Hibernate, monster that it is.