Hello,

On Wednesday, September 19, 2012 6:03:19 PM UTC+2, Lukas Eder wrote:
>
> Hello, 
>
> I've stumbled upon LLblgen a couple of times now, I'm sure I'll find 
> some good inspiration for jOOQ in there. However, 
>
> > //Relations to load (customer -> orders -> orderdetails and customer -> 
> > Address) 
> > IPrefetchPath prefetchPath = new PrefetchPath(); 
> > 
> prefetchPath.Add(CustomerEntity.PrefetchPathOrders).SubPath.Add(OrderEntity.PrefetchPathOrderDetails);
>  
>
> > 
> > prefetchPath.Add(CustomerEntity.PrefetchPathAddress); 
>
> At first sight, this syntax looks somewhat verbose to me, for the 
> little features it offers. In fact, it just avoids 1-2 join clauses, 
> if I understand this correctly? 


Entities in llblgen have accessors for all foreign entities, you may add or 
disable relations you don't need using their designer tool... Unless you 
use selfservicing, those are just plain C# objects that are serializable 
and remotable, unlike hibernate or such tools, they aren't proxies that 
references a database connection. They are mostly data holders.

Typically, an Order Entity may have a "CustomerEntity" or a 
"List<OrderDetailEntity>" among its properties if corresponding foreign 
keys are defined. 
PrefetchPath are there to explain which parts of the object graph you want 
the dataAdapter to load. The system may seem a bit awkward at first look, 
but consider this use case :

You want a list of customers from one region, you're also going to need 
their orders, their past purchases along with the order details and product 
of those. Loading these with one single query and JOINS, may give you so 
many duplicates in the resultset that you could quickly end up with one 
hundred of thousand rows so you'd prefer subqueries.

Your first SELECT from customer where region=x returns 350 customers. Now 
for those 350, you want to load their orders in one single query, then the 
order details of those in another subquery, you'd better love big routines 
and Hashmaps if you want to hand code that yourself. Even if you had some 
HQL like join logic, you'd still have to manually distribute the query 
result to the main collection, or you'd need a session cache which is 
probably not an attractive solution (after all, we are all using Jooq 
because we have grown sick and tired of hibernate-like voodoo frameworks 
right ;-) ?).

Using the prefetchPath API, you can do that in just a few lines of code, 
you d'write

IPrefetchPath prefetchPath = new PrefetchPath();
prefetchPath.Add(CustomerEntity.PrefetchPathOrders)

     .SubPath.Add(OrderEntity.PrefetchPathOrderDetails)

     .SubPath.Add(OrderDetailEntity.PrefetchPathProduct)


prefetchPath.Add(CustomerEntity.PrefetchPathPastPurchases)

     .SubPath.Add(PastPurchasEntity.PrefetchPathPastPurchasesDetails)

     .SubPath.Add(PastPurchaseDetailsEntity.PrefetchPathProduct)

You pass the prefetchPath object to the dataloader along with other stuff 
("where" filters) and it will populate graph branches stated above 
automatically by using subselects or IN queries depending on the number of 
rows returned. Then you just have to iterate the resulting entity 
collection and everything you asked for is there, without any N+1. It's 
extremely powerful and saves a lot of coding.

Unlike hibernate and HQL, it does not rely on a session cache to handle the 
graph magic, it just does what you ask. It's perfectly safe to pass the 
resulting objects to some service or to display it in the UI. 



Besides, I'd really prefer not to 
> expose some implementation internals (the notion of a path that is 
> "prefetched") in an API. If I'm going to go down that path, I'd really 
> love the resulting jOOQ code look something like this: 
>
> ----------------------------------------------------- 
> // Query 1 
> create.select(FIRST_NAME, LAST_NAME) 
>       .from(AUTHORS) 
>       .where(AUTHORS.BOOKS.TITLE.equal("1984")) 
>
> // Query 2 
> create.select(TITLE) 
>       .from(BOOKS) 
>       .where(BOOKS.AUTHORS.LAST_NAME.equal("Orwell")) 
> ----------------------------------------------------- 
>
> which would render this SQL 
>
> ----------------------------------------------------- 
> -- Query 1 
> SELECT first_name, last_name 
> FROM   authors 
> WHERE  EXISTS ( 
>   SELECT 1 FROM books 
>   WHERE books.author_id = author.id 
>   AND books.title = '1984' 
> ) 
>
> -- Query 2 
> SELECT title 
> FROM   books 
> JOIN   authors ON authors.id = books.author_id 
> WHERE  authors.last_name = 'Orwell' 
> ----------------------------------------------------- 
>
> As indicated in https://github.com/jOOQ/jOOQ/issues/1502. This would 
> resemble a typesafe HQL 
>
> > Because I never trusted this "full OO domain over relational" approach 
> > advertised by bookwriters and saw a lot of projects where category 2 led 
> to 
> > disaster, I choose "1" (mybatis) and had success doing so. Now I think 
> that 
> > Jooq, thanks to its code generation approach does a great job reducing 
> the 
> > drawbacks of category "1". I am just wondering if it could go even 
> further 
> > with some common issues such as loading relations. 
>
> Yes, it most certainly could. 
>

Reply via email to